/* ═══════════════════════════════════════════════════════════════════ Enduro Trails — Design System v5.0 Phase 5: Dual themes, skeleton, swipe, desktop, animations ═══════════════════════════════════════════════════════════════════ */ *,*::before,*::after{box-sizing:border-box;margin:0;padding:0} /* ── Dark Theme (default) ───── */ body.theme-dark { --bg: #0D1117; --surface: #161B22; --surface2: #21262D; --surface3: #2D333B; --border: #30363D; --border2: #444C56; --text: #E6EDF3; --text2: #8B949E; --text3: #484F58; --accent: #FF6B00; --accent-h: #FF8C2A; --accent-bg: rgba(255,107,0,0.12); --gold: #FFD700; --gold-bg: rgba(255,215,0,0.12); --red: #FF3B1F; --red-bg: rgba(255,59,31,0.12); --success: #2EA043; --shadow: 0 4px 24px rgba(0,0,0,0.6); --shadow-sm: 0 2px 8px rgba(0,0,0,0.4); --overlay: rgba(0,0,0,0.6); } /* ── Light Theme ────────────── */ body.theme-light { --bg: #F0EFE8; --surface: #FFFFFF; --surface2: #F5F4EE; --surface3: #ECEAE2; --border: #D4D0C8; --border2: #B8B4AA; --text: #1C1C1A; --text2: #6B6760; --text3: #9C9890; --accent: #D95200; --accent-h: #BF4800; --accent-bg: rgba(217,82,0,0.1); --gold: #A07800; --gold-bg: rgba(160,120,0,0.1); --red: #B82200; --red-bg: rgba(184,34,0,0.1); --success: #1A6B2A; --shadow: 0 4px 24px rgba(0,0,0,0.15); --shadow-sm: 0 2px 8px rgba(0,0,0,0.1); --overlay: rgba(0,0,0,0.3); } /* ── Base ─────────────────────────────────────── */ html, body { height: 100%; font-family: -apple-system, 'SF Pro Text', 'Segoe UI', system-ui, sans-serif; font-size: 14px; background: var(--bg); color: var(--text); overflow: hidden; -webkit-font-smoothing: antialiased; transition: background 0.3s, color 0.3s; } #map { position: fixed; inset: 0; z-index: 0; } /* ── MapLibre nav controls position ──────────── */ .maplibregl-ctrl-top-left { top: calc(max(env(safe-area-inset-top, 0px), 12px) + 8px) !important; left: 12px !important; } /* ── Waypoint inline search ───────────────────── */ .wl-search-btn { background: none; border: none; color: var(--text3); cursor: pointer; padding: 4px; border-radius: 6px; display: flex; align-items: center; flex-shrink: 0; transition: color 0.15s; } .wl-search-btn:hover, .wl-search-btn:active { color: var(--accent); } .wl-search-panel { padding: 6px 8px 4px 8px; border-top: 1px solid var(--border); } .wl-search-input { width: 100%; background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; color: var(--text); font-size: 13px; padding: 7px 10px; outline: none; box-sizing: border-box; } .wl-search-input:focus { border-color: var(--accent); } .wl-search-results { margin-top: 4px; max-height: 180px; overflow-y: auto; } .wl-search-result-item { padding: 8px 10px; cursor: pointer; border-radius: 6px; font-size: 13px; color: var(--text); } .wl-search-result-item:hover, .wl-search-result-item:active { background: var(--surface2); } .wl-search-result-name { font-weight: 500; } .wl-search-result-sub { font-size: 11px; color: var(--text2); margin-top: 1px; } /* ── Map Control Buttons ──────────────────────── */ #map-controls-r { position: fixed; right: 12px; bottom: calc(80px + env(safe-area-inset-bottom, 0px) + 12px); display: flex; flex-direction: column; gap: 8px; z-index: 400; transition: bottom 0.2s ease; } .map-btn { width: 48px; height: 48px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; color: var(--text2); display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: var(--shadow-sm); transition: all 0.15s; -webkit-tap-highlight-color: transparent; position: relative; } .map-btn svg { width: 20px; height: 20px; } .map-btn:active { transform: scale(0.94); background: var(--surface2); } .map-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); } /* ── Bottom Toolbar ───────────────────────────── */ #toolbar { position: fixed; bottom: 0; left: 0; right: 0; height: calc(68px + env(safe-area-inset-bottom, 0px)); padding-bottom: env(safe-area-inset-bottom, 0px); background: var(--surface); border-top: 1px solid var(--border); display: flex; align-items: center; justify-content: space-around; z-index: 300; box-shadow: 0 -4px 20px rgba(0,0,0,0.2); transition: background 0.3s, border-color 0.3s; } .tb-btn { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; height: 56px; border: none; background: none; color: var(--text3); font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; border-radius: 10px; cursor: pointer; transition: color 0.15s, background 0.15s, transform 0.1s; -webkit-tap-highlight-color: transparent; padding: 0 4px; } .tb-btn svg { width: 22px; height: 22px; margin-bottom: 1px; transition: transform 0.1s; } .tb-btn:active { background: var(--surface2); transform: scale(0.94); } .tb-btn.active { color: #fff; background: var(--accent); border-radius: 10px; } .tb-btn.active svg { stroke: #fff; } .tb-btn span { line-height: 1; } /* ── Bottom Sheet ─────────────────────────────── */ .bottom-sheet { position: fixed; bottom: 0; left: 0; right: 0; background: var(--surface); border-radius: 20px 20px 0 0; border-top: 1px solid var(--border); z-index: 400; max-height: 78vh; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; transform: translateY(100%); transition: transform 0.3s cubic-bezier(0.32, 0, 0.15, 1); padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px)); touch-action: pan-y; } .bottom-sheet.open { transform: translateY(0); } .bottom-sheet.swiping { transition: none; } .sheet-handle { width: 36px; height: 4px; background: var(--border2); border-radius: 2px; margin: 12px auto 0; cursor: grab; } .sheet-header { display: flex; align-items: center; padding: 14px 16px 12px; gap: 10px; border-bottom: 1px solid var(--border); } .sheet-header svg { width: 20px; height: 20px; stroke: var(--accent); flex-shrink: 0; } .sheet-header h2 { flex: 1; font-size: 15px; font-weight: 700; color: var(--text); letter-spacing: 0.02em; } .sheet-close { width: 32px; height: 32px; border-radius: 8px; background: var(--surface2); border: 1px solid var(--border); color: var(--text2); display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; transition: all 0.15s; } .sheet-close svg { width: 16px; height: 16px; } .sheet-close:active { background: var(--surface3); color: var(--text); } .sheet-body { padding: 14px 16px; } .sheet-hint { font-size: 13px; color: var(--text2); text-align: center; padding: 16px 0 8px; line-height: 1.5; } #sheet-backdrop { position: fixed; inset: 0; background: var(--overlay); z-index: 390; opacity: 0; pointer-events: none; transition: opacity 0.3s; } #sheet-backdrop.visible { opacity: 1; pointer-events: auto; } /* Allow map clicks through backdrop when route/ruler/marker/recon/link/scenic mode is active */ body.has-map-mode #sheet-backdrop.visible { pointer-events: none; } /* ── Section Label ────────────────────────────── */ .section-label { font-size: 10px; font-weight: 800; color: var(--text3); text-transform: uppercase; letter-spacing: 0.12em; margin-bottom: 8px; margin-top: 4px; } /* ── Waypoints Row ────────────────────────────── */ .waypoints-row { display: flex; align-items: center; gap: 4px; overflow-x: auto; padding: 0 0 4px; scrollbar-width: none; } .waypoints-row::-webkit-scrollbar { display: none; } .wp-chip { display: flex; align-items: center; gap: 6px; background: var(--surface2); border: 1px solid var(--border); border-radius: 10px; padding: 7px 10px; flex-shrink: 0; max-width: 140px; cursor: pointer; transition: border-color 0.15s; } .wp-chip:active { border-color: var(--accent); } .wp-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; } .wp-label { font-size: 12px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .wp-arrow { color: var(--text3); font-size: 18px; flex-shrink: 0; padding: 0 1px; } .wp-add { display: flex; align-items: center; gap: 6px; background: none; border: 1.5px dashed var(--border2); border-radius: 10px; padding: 7px 12px; font-size: 12px; font-weight: 600; color: var(--text2); flex-shrink: 0; cursor: pointer; transition: border-color 0.15s, color 0.15s; } .wp-add:active { border-color: var(--accent); color: var(--accent); } /* ── Waypoints List ───────────────────────────── */ #waypoints-list { display: flex; flex-direction: column; margin-bottom: 10px; } .wl-item { display: flex; align-items: center; gap: 8px; padding: 8px 4px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; border-bottom: 1px solid var(--border); position: relative; } .wl-item:last-child { border-bottom: none; } .wl-drag-handle { width: 20px; height: 28px; display: flex; align-items: center; justify-content: center; color: var(--text3); cursor: grab; flex-shrink: 0; touch-action: none; -webkit-tap-highlight-color: transparent; } .wl-drag-handle svg { width: 16px; height: 16px; } .wl-item.dragging { opacity: 0.4; background: var(--surface); border-radius: 4px; } .wl-item.drag-over-top { border-top: 2px solid var(--accent); } .wl-item.drag-over-bottom { border-bottom: 2px solid var(--accent); } .wl-pin { flex-shrink: 0; display: flex; align-items: center; } .wl-info { display: flex; flex-direction: column; flex: 1; min-width: 0; } .wl-label { font-size: 13px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .wl-dist { font-size: 11px; color: var(--text3); margin-top: 1px; } .wl-remove { width: 28px; height: 28px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; background: none; border: none; color: var(--text3); cursor: pointer; border-radius: 6px; -webkit-tap-highlight-color: transparent; } .wl-remove:active { background: var(--red-bg); color: var(--red); } .wl-remove svg { width: 14px; height: 14px; } /* Sheet icon buttons (header) */ .sheet-icon-btn { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; background: none; border: none; color: var(--text3); border-radius: 8px; cursor: pointer; padding: 0; flex-shrink: 0; transition: background 0.15s, color 0.15s; -webkit-tap-highlight-color: transparent; } .sheet-icon-btn svg { width: 18px; height: 18px; } .sheet-icon-btn:active { background: var(--surface2); } .sheet-icon-btn.danger { color: var(--red); } .sheet-icon-btn.danger:active { background: var(--red); color: #fff; } /* Add waypoint row */ .wl-add { cursor: pointer; } .wl-add:active { background: var(--surface); } .wl-add .wl-pin svg path { fill: var(--text3) !important; } .wl-add .wl-label { color: var(--text3); } /* ── Route Status ─────────────────────────────── */ #route-status { font-size: 13px; color: var(--text2); padding: 8px 0; display: flex; align-items: center; gap: 6px; min-height: 20px; } /* ── Route Cards ──────────────────────────────── */ #route-cards, #link-cards, #scenic-cards { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; } .route-card { background: var(--surface2); border: 1.5px solid var(--border); border-left: 4px solid transparent; border-radius: 10px; padding: 10px 12px; margin-bottom: 0; cursor: pointer; transition: border-color 0.15s, background 0.15s; -webkit-tap-highlight-color: transparent; animation: cardFadeIn 0.2s ease-out both; } .route-card:active { background: var(--surface3, var(--surface2)); } .route-card.active { border-color: var(--border); border-left-color: var(--accent); background: var(--accent-bg); } .rc-header { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; } .rc-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; } .rc-title { font-size: 13px; font-weight: 700; color: var(--text); flex: 1; } .rc-meta { font-size: 12px; color: var(--text2); white-space: nowrap; font-variant-numeric: tabular-nums; } .rc-bar-wrap { margin-bottom: 4px; } .rc-bar { height: 6px; border-radius: 3px; background: var(--border); display: flex; overflow: hidden; } .rc-bar-dirt { background: var(--gold); border-radius: 3px 0 0 3px; transition: width 0.4s; } .rc-bar-asphalt { background: var(--text3); } .rc-bar-label { font-size: 11px; color: var(--text2); } .rc-stats { display: flex; flex-wrap: wrap; gap: 5px; } /* Stat pills */ .stat-pill { display: inline-flex; align-items: center; gap: 4px; border-radius: 20px; padding: 3px 9px; font-size: 11px; font-weight: 700; letter-spacing: 0.02em; } .stat-pill.dirt { background: var(--gold-bg); color: var(--gold); } .stat-pill.asphalt { background: var(--surface3); color: var(--text2); } .stat-pill.path { background: var(--red-bg); color: var(--red); } /* ── Primary Button ───────────────────────────── */ .btn-primary { width: 100%; height: 48px; background: var(--accent); color: #fff; border: none; border-radius: 14px; font-size: 15px; font-weight: 700; display: flex; align-items: center; justify-content: center; gap: 8px; cursor: pointer; transition: background 0.15s, transform 0.1s; letter-spacing: 0.02em; margin-top: 12px; } .btn-primary svg { width: 18px; height: 18px; } .btn-primary:active { background: var(--accent-h); transform: scale(0.98); } .btn-primary:disabled { opacity: 0.5; pointer-events: none; } /* ── Segment Control ──────────────────────────── */ .seg-control { display: flex; gap: 4px; background: var(--surface2); border: 1px solid var(--border); border-radius: 12px; padding: 4px; margin-bottom: 12px; } .seg-btn { flex: 1; height: 34px; background: none; border: none; border-radius: 9px; font-size: 13px; font-weight: 600; color: var(--text2); cursor: pointer; transition: all 0.15s; } .seg-btn.active { background: var(--accent); color: #fff; box-shadow: 0 2px 8px rgba(255,107,0,0.35); } .seg-btn:not(.active):active { background: var(--surface3); } .dist-custom { height: 34px; width: 70px; background: var(--surface2); border: 1px solid var(--border); border-radius: 9px; color: var(--text); font-size: 13px; font-weight: 600; text-align: center; outline: none; flex-shrink: 0; } .dist-custom:focus { border-color: var(--accent); } /* ── Recon Results ────────────────────────────── */ .recon-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 14px; } .recon-stat { background: var(--surface2); border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; } .rs-value { font-size: 22px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; line-height: 1; margin-bottom: 3px; } .rs-value.gold { color: var(--gold); } .rs-value.red { color: var(--red); } .rs-label { font-size: 11px; color: var(--text2); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; } .poi-row { display: flex; align-items: center; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid var(--border); } .poi-row:last-child { border-bottom: none; } .poi-row-label { font-size: 13px; color: var(--text); display: flex; align-items: center; gap: 8px; } .poi-row-count { font-size: 16px; font-weight: 800; color: var(--accent); font-variant-numeric: tabular-nums; } .poi-icon { width: 28px; height: 28px; border-radius: 8px; background: var(--surface2); display: flex; align-items: center; justify-content: center; font-size: 14px; } /* ── Scenic POI ───────────────────────────────── */ .scenic-poi-item { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text2); padding: 3px 0; } .scenic-score-bar { height: 4px; border-radius: 2px; background: var(--surface3); overflow: hidden; margin: 6px 0; } .scenic-score-fill { height: 100%; background: var(--gold); border-radius: 2px; } /* ── Link Points ──────────────────────────────── */ .link-points { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; } .link-pt { display: flex; align-items: center; gap: 8px; background: var(--surface2); border: 1.5px solid var(--border); border-radius: 10px; padding: 10px 12px; } .link-pt-num { width: 24px; height: 24px; border-radius: 50%; background: var(--accent); color: #fff; font-size: 12px; font-weight: 800; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .link-pt-label { font-size: 13px; color: var(--text); flex: 1; } .link-pt.empty .link-pt-num { background: var(--surface3); color: var(--text3); } .link-pt.empty .link-pt-label { color: var(--text3); } #link-status { font-size: 13px; color: var(--text2); padding: 4px 0 10px; } /* ── Scenic Config ───────────────────────────── */ #scenic-status { font-size: 13px; color: var(--text2); padding: 6px 0; display: flex; align-items: center; gap: 6px; } .dist-row { display: flex; gap: 4px; align-items: center; margin-bottom: 4px; } /* ── Marker Dialog ────────────────────────────── */ #marker-dialog { position: fixed; inset: 0; z-index: 500; display: flex; align-items: flex-end; justify-content: center; padding-bottom: env(safe-area-inset-bottom, 0px); pointer-events: none; opacity: 0; transition: opacity 0.2s; } #marker-dialog.open { pointer-events: auto; opacity: 1; } .marker-dialog-inner { background: var(--surface); border-radius: 20px 20px 0 0; border-top: 1px solid var(--border); padding: 0 16px 20px; width: 100%; transform: translateY(30px); transition: transform 0.25s cubic-bezier(0.32, 0, 0.15, 1); } #marker-dialog.open .marker-dialog-inner { transform: translateY(0); } .marker-type-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; padding: 12px 0; } .marker-type-btn { background: var(--surface2); border: 1.5px solid var(--border); border-radius: 12px; padding: 12px 8px; cursor: pointer; transition: all 0.15s; display: flex; flex-direction: column; align-items: center; gap: 5px; -webkit-tap-highlight-color: transparent; } .marker-type-btn:active { border-color: var(--accent); background: var(--accent-bg); } .marker-type-btn .mt-icon { font-size: 24px; } .marker-type-btn .mt-label { font-size: 11px; font-weight: 600; color: var(--text2); text-transform: uppercase; letter-spacing: 0.06em; } /* ── No Data Warning ─────────────────────────── */ #no-data-warning { display: none; position: fixed; bottom: 80px; left: 12px; right: 12px; background: var(--red-bg); border: 1px solid var(--red); border-radius: 12px; padding: 10px 14px; font-size: 13px; color: var(--red); z-index: 200; } #no-data-warning.visible { display: block; } /* ── Skeleton Loading ────────────────────────── */ .skeleton { background: linear-gradient(90deg, var(--surface2) 0%, var(--surface3) 50%, var(--surface2) 100%); background-size: 200% 100%; animation: shimmer 1.4s infinite; border-radius: 8px; } @keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } .skeleton-card { background: var(--surface2); border: 1.5px solid var(--border); border-radius: 14px; padding: 14px; margin-bottom: 8px; } .skeleton-line { height: 14px; margin-bottom: 8px; border-radius: 4px; } .skeleton-line.w60 { width: 60%; } .skeleton-line.w40 { width: 40%; } .skeleton-line.w80 { width: 80%; } .skeleton-line.h20 { height: 20px; } /* ── Ruler ───────────────────────────────────── */ #ruler-info { position: fixed; top: calc(max(env(safe-area-inset-top,0px),12px) + 58px); left: 50%; transform: translateX(-50%); width: fit-content; max-width: 320px; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 5px 10px; font-size: 13px; color: var(--text); font-weight: 600; z-index: 200; display: none; box-shadow: var(--shadow-sm); } #ruler-info.visible { display: flex; align-items: center; gap: 6px; } #ruler-info #ruler-dist { flex: 1; } .ruler-action-btn { flex-shrink: 0; height: 32px; min-width: 32px; padding: 4px 10px; background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; color: var(--text); font-size: 13px; font-weight: 600; cursor: pointer; white-space: nowrap; display: flex; align-items: center; justify-content: center; -webkit-tap-highlight-color: transparent; } .ruler-action-btn--danger { color: var(--danger, #e05252); border-color: var(--danger, #e05252); font-size: 16px; padding: 4px 8px; } /* ── Ruler toast hint ────────────────────────── */ #ruler-toast { position: fixed; top: calc(max(env(safe-area-inset-top,0px),12px) + 100px); left: 50%; transform: translateX(-50%); background: rgba(20,20,20,0.82); color: #fff; font-size: 13px; font-weight: 600; padding: 8px 16px; border-radius: 20px; z-index: 210; pointer-events: none; opacity: 0; transition: opacity 0.3s; white-space: nowrap; } #ruler-toast.visible { opacity: 1; } /* ── Fix: MapLibre markers must stay absolute ────── */ .maplibregl-marker { position: absolute !important; } /* ── Waypoint Markers ─────────────────────────── */ .route-waypoint-marker { filter: drop-shadow(0 2px 4px rgba(0,0,0,0.4)); width: 28px; height: 36px; cursor: grab; display: block; } .route-waypoint-marker:active { cursor: grabbing; } .named-marker-el { font-size: 22px; cursor: pointer; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.5)); user-select: none; line-height: 1; display: block; width: 28px; height: 28px; text-align: center; } /* ═══════════════════════════════════════════════════ TASK 5: Desktop Layout (≥768px) ═══════════════════════════════════════════════════ */ @media (min-width: 768px) { #toolbar { flex-direction: column; width: 72px; height: auto; right: auto; left: 0; top: 0; bottom: 0; border-right: 1px solid var(--border); border-top: none; padding: 80px 0 20px; justify-content: flex-start; gap: 4px; } .tb-btn { width: 64px; height: 56px; flex: none; } .bottom-sheet { left: 72px; right: auto; width: 380px; max-width: 400px; max-height: 100vh; border-radius: 0 20px 0 0; border-top: none; border-right: 1px solid var(--border); top: 0; bottom: 0; transform: translateX(-120%); } .bottom-sheet.open { transform: translateX(0); } .bottom-sheet.swiping { transition: none; } #map-controls-r { right: 12px; bottom: 12px; } #sheet-backdrop { display: none; } #ruler-info { max-width: 320px; } } /* ═══════════════════════════════════════════════════ TASK 6: Micro-animations ═══════════════════════════════════════════════════ */ @keyframes cardFadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } .route-card:nth-child(1) { animation-delay: 0ms; } .route-card:nth-child(2) { animation-delay: 60ms; } .route-card:nth-child(3) { animation-delay: 120ms; } .route-card:nth-child(4) { animation-delay: 180ms; } .route-card:nth-child(5) { animation-delay: 240ms; } /* Marker pop-in animation */ @keyframes markerPopIn { from { transform: scale(0); opacity: 0; } to { transform: scale(1); opacity: 1; } } /* marker-anim НЕ применять к элементам-обёрткам MapLibre — только к внутренним элементам */ .marker-anim-inner { animation: markerPopIn 0.2s cubic-bezier(0.18, 0.89, 0.32, 1.28) both; } /* ── Onboarding (empty waypoints state) ─────────── */ .wl-onboarding { padding: 4px 0; } .wl-onboard-field { display: flex; align-items: flex-start; gap: 10px; padding: 8px 12px 8px 0; } .wl-onboard-input { flex: 1; background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; color: var(--text); font-size: 14px; padding: 8px 12px; outline: none; box-sizing: border-box; } .wl-onboard-input:focus { border-color: var(--accent); } .wl-onboard-hint { text-align: center; font-size: 12px; color: var(--text3); padding: 4px 0 8px; } /* ── Misc ────────────────────────────────────── */ .text-accent { color: var(--accent); } .text-gold { color: var(--gold); } .text-red { color: var(--red); } .text-muted { color: var(--text2); } .mt-8 { margin-top: 8px; } .mt-12 { margin-top: 12px; } .mb-8 { margin-bottom: 8px; } .cursor-crosshair .maplibregl-canvas { cursor: crosshair !important; } /* ── My Location Marker ──────────────────────── */ .my-location-marker { position: relative; width: 20px; height: 20px; } .my-location-dot { position: absolute; top: 50%; left: 50%; width: 12px; height: 12px; background: #4285f4; border: 2px solid #fff; border-radius: 50%; transform: translate(-50%, -50%); box-shadow: 0 2px 6px rgba(66,133,244,0.6); } .my-location-pulse { position: absolute; top: 50%; left: 50%; width: 30px; height: 30px; background: rgba(66,133,244,0.3); border-radius: 50%; transform: translate(-50%, -50%); animation: pulse-ring 2s ease-out infinite; } @keyframes pulse-ring { 0% { transform: translate(-50%, -50%) scale(0.5); opacity: 1; } 100% { transform: translate(-50%, -50%) scale(2); opacity: 0; } } /* ── MapLibre popup theme overrides ──────────── */ .maplibregl-popup-content { background: var(--surface) !important; color: var(--text) !important; border: 1px solid var(--border) !important; border-radius: 12px !important; padding: 12px !important; font-size: 13px; box-shadow: var(--shadow) !important; } .maplibregl-popup-tip { border-top-color: var(--surface) !important; } .maplibregl-popup-close-button { color: var(--text2) !important; font-size: 18px !important; right: 6px !important; top: 4px !important; } .popup-title { font-size: 14px; font-weight: 700; color: var(--text); margin-bottom: 4px; } .popup-row { display: flex; justify-content: space-between; padding: 2px 0; font-size: 12px; } .popup-key { color: var(--text2); } .popup-val { color: var(--text); font-weight: 600; } /* Route card legacy styles (compat) */ .route-card-header { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; } .route-color-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; } .route-card-title { flex: 1; font-size: 13px; font-weight: 700; color: var(--text); } .route-card-dist { font-size: 14px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; } .route-card-time { font-size: 12px; color: var(--text2); font-variant-numeric: tabular-nums; } .route-coverage-bar { height: 5px; border-radius: 3px; background: var(--surface3); overflow: hidden; margin-bottom: 8px; display: flex; } .route-coverage-bar > div { height: 100%; transition: width 0.4s; } .route-card-summary { font-size: 12px; color: var(--text2); margin-bottom: 6px; } .route-card-details { margin-top: 6px; border-top: 1px solid var(--border); padding-top: 6px; } .route-stat-row { font-size: 12px; color: var(--text2); padding: 2px 0; } .route-details-toggle { width: 100%; background: none; border: none; color: var(--accent); font-size: 12px; font-weight: 600; cursor: pointer; padding: 6px 0 0; text-align: left; } .waypoint-row { display: flex; align-items: center; gap: 8px; padding: 6px 8px; background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; margin-bottom: 4px; transition: border-color 0.15s; } .waypoint-row.drag-over { border-color: var(--accent); } .waypoint-label { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 50%; font-size: 11px; font-weight: 700; color: #fff; flex-shrink: 0; } .waypoint-label.start { background: var(--success); } .waypoint-label.end { background: var(--red); } .waypoint-label.mid { background: #0066ff; } .waypoint-coords { flex: 1; font-size: 12px; color: var(--text2); font-variant-numeric: tabular-nums; } .waypoint-remove { width: 24px; height: 24px; border: none; background: none; color: var(--text3); cursor: pointer; font-size: 14px; border-radius: 4px; display: flex; align-items: center; justify-content: center; } .waypoint-remove:hover { background: var(--red-bg); color: var(--red); } #btn-add-waypoint { width: 100%; height: 36px; background: var(--surface2); border: 1.5px dashed var(--border2); border-radius: 10px; color: var(--text2); font-size: 12px; font-weight: 600; cursor: pointer; margin-top: 4px; display: flex; align-items: center; justify-content: center; gap: 6px; transition: border-color 0.15s; } #btn-add-waypoint:hover { border-color: var(--accent); color: var(--accent); } #btn-build-route { width: 100%; height: 42px; background: var(--accent); color: #fff; border: none; border-radius: 10px; font-size: 14px; font-weight: 700; cursor: pointer; margin-top: 8px; transition: background 0.15s; } #btn-build-route:active { background: var(--accent-h); } /* ── Mini Route Bar ───────────────────────── */ #sheet-route-mini { position: fixed; bottom: 72px; left: 0; right: 0; height: 64px; background: var(--surface); border-top: 1px solid var(--border); border-radius: 14px 14px 0 0; z-index: 350; display: none; flex-direction: column; align-items: center; box-shadow: 0 -4px 16px var(--shadow); } #sheet-route-mini.visible { display: flex; } #sheet-route-mini .mini-handle { width: 32px; height: 4px; background: var(--border2, var(--border)); border-radius: 2px; margin: 7px auto 0; flex-shrink: 0; } .mini-route-info { display: flex; align-items: center; gap: 10px; padding: 0 16px; flex: 1; width: 100%; } .mini-route-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; } .mini-route-text { flex: 1; min-width: 0; } .mini-route-label { font-size: 13px; font-weight: 700; color: var(--text); } .mini-route-stats { font-size: 11px; color: var(--text2); } .mini-route-arrows { display: flex; gap: 6px; flex-shrink: 0; margin-left: 8px; } .mini-arrow { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; background: var(--surface2); border: 1px solid var(--border); border-radius: 10px; font-size: 22px; color: var(--text2); cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent; } .mini-arrow:active { background: var(--accent); color: #fff; border-color: var(--accent); } .mini-add-btn { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; background: var(--accent); border: none; border-radius: 10px; color: #fff; cursor: pointer; flex-shrink: 0; margin-left: 4px; -webkit-tap-highlight-color: transparent; } .mini-add-btn:active { opacity: 0.8; transform: scale(0.94); } /* ── Route onboarding mini-bar ───────────────── */ #mini-onboard-pin svg { width: 22px; height: 28px; } @media (min-width: 768px) { #sheet-route-mini { left: 72px; width: 380px; right: auto; border-radius: 0 14px 0 0; } } /* ── Route Loading Spinner ───────────────────── */ .route-loading { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 32px 16px; } .route-spinner { width: 32px; height: 32px; border: 3px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.8s linear infinite; } /* ── Moto Wheel Loading Indicator ────────────── */ .moto-wheel { width: 32px; height: 32px; flex-shrink: 0; display: none; transform-origin: center; } .moto-wheel.spinning { display: block; animation: wheelSpin 0.8s linear infinite; } @keyframes wheelSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } /* ═══════════════════════════════════════════ Terrain Layer (Phase 5.4) ═══════════════════════════════════════════ */ /* Terrain toggle button active state */ #terrain-toggle.active { color: var(--accent, #4CAF50); background: rgba(76, 175, 80, 0.15); } /* Terrain popup */ .terrain-popup { position: fixed; z-index: 500; background: var(--surface, #1e1e1e); border: 1px solid var(--border, rgba(255,255,255,0.12)); border-radius: 12px; padding: 12px 14px; min-width: 160px; box-shadow: 0 4px 20px rgba(0,0,0,0.4); user-select: none; } .terrain-popup-title { font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text2, rgba(255,255,255,0.5)); margin-bottom: 10px; } .terrain-checkbox { display: flex; align-items: center; gap: 10px; padding: 8px 4px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; cursor: pointer; font-size: 15px; color: var(--text, #fff); border-radius: 6px; } .terrain-checkbox span { font-size: 15px; line-height: 1.3; } .terrain-checkbox:hover { color: var(--accent, #4CAF50); } .terrain-checkbox input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--accent, #4CAF50); cursor: pointer; flex-shrink: 0; } /* Light theme overrides */ .theme-light .terrain-popup { background: var(--surface, #fff); border-color: var(--border, rgba(0,0,0,0.12)); box-shadow: 0 4px 20px rgba(0,0,0,0.15); } .theme-light .terrain-popup-title { color: var(--text2, rgba(0,0,0,0.5)); } .theme-light .terrain-checkbox { color: var(--text, #111); } /* Terrain hillshade hint & disabled state */ .terrain-hint { display: block; font-size: 11px; color: var(--accent, #4CAF50); font-style: italic; padding: 4px 0 2px 28px; line-height: 1.2; } .terrain-checkbox.disabled { opacity: 0.45; pointer-events: none; cursor: not-allowed; } .terrain-checkbox.disabled input[type="checkbox"] { cursor: not-allowed; } /* ── ET-007: переключатель подложки (Схема/Спутник) в попапе рельефа ── */ .terrain-base-row { display: flex; align-items: center; gap: 8px; padding: 4px 0 2px; } .terrain-base-label { font-size: 12px; color: var(--text2); flex-shrink: 0; } .terrain-base-row .seg-control { flex: 1; margin-bottom: 0; } .base-seg .seg-btn { font-size: 12px; height: 34px; } /* ET-007 P1-5 / ADR-004 §8: пока активен «Спутник», скрыть UI-кнопку «Базовая карта» (#btn-basemap) — гибридный режим (схема поверх спутника) out of scope BRD §3. JS добавляет/снимает класс .satellite-active на в applyBaseLayer(). На «Схеме» — кнопка снова видна (если она присутствует в текущей вёрстке). */ body.satellite-active #btn-basemap { display: none !important; } /* ── ET-005: переключатель единиц измерения (км/мили) в попапе рельефа ── */ .terrain-unit-row { padding: 8px 4px 2px; } .terrain-unit-label { display: block; font-size: 15px; line-height: 1.3; color: var(--text, #fff); margin-bottom: 8px; } .theme-light .terrain-unit-label { color: var(--text, #111); } /* Сегментированный переключатель внутри попапа — без нижнего отступа, он последний элемент (см. .seg-control в блоке Segment Control). */ .terrain-unit-row .seg-control { margin-bottom: 0; } /* ── Scale + Zoom bar (one line, top-right) ───────── */ #scale-zoom-bar { position: absolute; top: calc(max(env(safe-area-inset-top, 0px), 8px) + 4px); right: 12px; display: flex; align-items: center; gap: 6px; z-index: 10; pointer-events: none; } .szb-scale { height: 16px; border: 1.5px solid rgba(255,255,255,0.8); border-top: none; display: flex; align-items: center; justify-content: center; min-width: 40px; } .szb-label { font-size: 10px; font-weight: 500; color: rgba(255,255,255,0.9); text-shadow: 0 0 3px rgba(0,0,0,0.8), 0 1px 2px rgba(0,0,0,0.6); white-space: nowrap; padding: 0 4px; } .szb-zoom { font-size: 11px; font-weight: 600; color: rgba(255,255,255,0.85); text-shadow: 0 0 3px rgba(0,0,0,0.8), 0 1px 2px rgba(0,0,0,0.6); white-space: nowrap; } /* ── Search panel ───────────────────────────── */ #search-panel { position: fixed; bottom: calc(68px + env(safe-area-inset-bottom, 0px)); left: 0; right: 0; background: var(--surface); border-top: 1px solid var(--border); z-index: 350; padding: 12px 16px; box-shadow: 0 -4px 20px rgba(0,0,0,0.15); } .search-panel-inner { display: flex; gap: 8px; align-items: center; } #standalone-search-input { flex: 1; background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; padding: 10px 14px; font-size: 15px; color: var(--text1); outline: none; } #standalone-search-input:focus { border-color: var(--accent); } #search-close-btn { background: none; border: none; color: var(--text3); font-size: 20px; cursor: pointer; padding: 4px 8px; } #standalone-search-results { max-height: 240px; overflow-y: auto; margin-top: 8px; } #standalone-search-results .search-result-item { padding: 10px 12px; border-radius: 8px; cursor: pointer; transition: background 0.15s; } #standalone-search-results .search-result-item:hover, #standalone-search-results .search-result-item:active { background: var(--surface2); } #standalone-search-results .search-result-name { font-size: 14px; font-weight: 500; color: var(--text1); } #standalone-search-results .search-result-sub { font-size: 12px; color: var(--text3); margin-top: 2px; } /* ─── Zoom controls ──────────────────────────────────────────────────────── */ #zoom-controls { position: fixed; left: 12px; top: 12px; display: flex; flex-direction: column; align-items: center; gap: 2px; z-index: 400; } #zoom-controls .map-btn { width: 40px; height: 40px; font-size: 20px; font-weight: 700; line-height: 1; } #zoom-level { background: var(--surface, #1e1e1e); color: var(--text, #fff); border-radius: 6px; padding: 4px 8px; font-size: 13px; font-weight: 600; min-width: 32px; text-align: center; border: 1px solid rgba(255,255,255,0.1); } /* ─── Scale bar ──────────────────────────────────────────────────────────── */ #scale-bar { position: fixed; bottom: calc(80px + env(safe-area-inset-bottom, 0px) + 16px); left: 12px; display: flex; flex-direction: column; align-items: flex-start; gap: 3px; z-index: 400; pointer-events: none; } #scale-line { height: 4px; width: 100px; background: #fff; border: 1px solid rgba(0,0,0,0.6); border-top: none; border-left: 2px solid #fff; border-right: 2px solid #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.5); } #scale-label { font-size: 11px; color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,0.9), 0 0 4px rgba(0,0,0,0.7); font-weight: 700; letter-spacing: 0.3px; } /* ═══════════════════════════════════════════════════ ET-006: Загрузка и визуализация GPX-треков ═══════════════════════════════════════════════════ */ /* ── Toast-уведомления (TRZ §3.4) ───────────────── */ #app-toast { position: fixed; top: calc(max(env(safe-area-inset-top,0px),12px) + 60px); left: 50%; transform: translateX(-50%); max-width: 86vw; background: rgba(20,20,20,0.92); color: #fff; font-size: 13px; font-weight: 600; text-align: center; padding: 10px 18px; border-radius: 20px; z-index: 600; pointer-events: none; opacity: 0; transition: opacity 0.3s; } #app-toast.visible { opacity: 1; } /* ── Индикатор парсинга GPX (TRZ REQ-NF-01, AC-11) ─ */ #gpx-loading { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); display: none; flex-direction: column; align-items: center; gap: 10px; background: var(--surface); border: 1px solid var(--border); border-radius: 14px; padding: 20px 28px; box-shadow: var(--shadow); z-index: 600; } #gpx-loading.visible { display: flex; } #gpx-loading span { font-size: 13px; color: var(--text2); font-weight: 600; } .gpx-spinner { width: 32px; height: 32px; border: 3px solid var(--surface3); border-top-color: var(--accent); border-radius: 50%; animation: gpx-spin 0.8s linear infinite; } @keyframes gpx-spin { to { transform: rotate(360deg); } } /* ── Список загруженных треков (TRZ §3.3) ───────── */ #gpx-list { display: flex; flex-direction: column; gap: 6px; } .gpx-row { display: flex; align-items: center; gap: 10px; background: var(--surface2); border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; cursor: pointer; transition: border-color 0.15s, background 0.15s; } .gpx-row:active { background: var(--surface3); } .gpx-row.active { border-color: var(--accent); background: var(--accent-bg); } .gpx-dot { width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0; box-shadow: 0 0 0 2px var(--surface); } .gpx-name { flex: 1; font-size: 13px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .gpx-check { color: var(--accent); font-weight: 800; font-size: 14px; } .gpx-del { width: 28px; height: 28px; flex-shrink: 0; border: 1px solid var(--border); background: var(--surface); color: var(--text2); border-radius: 8px; font-size: 13px; line-height: 1; cursor: pointer; transition: all 0.15s; } .gpx-del:active { background: var(--red); color: #fff; border-color: var(--red); } /* ── Сетка статистики трека (TRZ REQ-F-11) ──────── */ .gpx-stats-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin-bottom: 14px; } .gpx-stat { background: var(--surface2); border: 1px solid var(--border); border-radius: 10px; padding: 8px 4px; text-align: center; } .gpx-stat-val { font-size: 14px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; line-height: 1.1; } .gpx-stat-lbl { font-size: 9px; color: var(--text2); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; margin-top: 3px; } /* ── Профиль высот (TRZ REQ-F-10) ───────────────── */ #gpx-elevation-wrap { position: relative; width: 100%; } #gpx-elevation-canvas { display: block; width: 100%; height: 120px; background: var(--surface2); border: 1px solid var(--border); border-radius: 10px; touch-action: none; } #gpx-elevation-empty { font-size: 13px; color: var(--text2); text-align: center; padding: 38px 0; } #gpx-elevation-tip { position: absolute; top: 4px; display: none; background: rgba(20,20,20,0.92); color: #fff; font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: 8px; white-space: nowrap; pointer-events: none; } #gpx-elevation-axis { display: flex; justify-content: space-between; margin-top: 4px; font-size: 10px; color: var(--text3); font-weight: 600; } /* ── Маркер-курсор профиля на карте ─────────────── */ .gpx-cursor-marker { width: 12px; height: 12px; border-radius: 50%; background: var(--accent); border: 2px solid #fff; box-shadow: 0 1px 4px rgba(0,0,0,0.5); } /* ─── ET-008: GPS-треки ──────────────────────────── */ .terrain-link-btn { display: block; margin: 4px 0 0 24px; background: none; border: none; color: var(--accent, #ff8c1a); font-size: 12px; cursor: pointer; padding: 2px 0; text-decoration: underline; } .gps-filter-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-bottom: 12px; } .gps-filter-chip { display: flex; align-items: center; gap: 6px; cursor: pointer; font-size: 13px; color: var(--text); } .gps-filter-chip input[type=checkbox] { accent-color: var(--accent, #ff8c1a); width: 14px; height: 14px; } .gps-stats-row { font-size: 12px; color: var(--text2); margin-top: 8px; } /* Track popup */ .track-popup { font-size: 13px; color: var(--text, #fff); min-width: 220px; } .track-popup-name { font-weight: 700; font-size: 14px; margin-bottom: 6px; } .track-popup-row { margin: 3px 0; color: var(--text2, #ccc); } .track-popup-sources { margin-top: 8px; font-size: 12px; } .track-popup-sources a { color: var(--accent, #ff8c1a); text-decoration: none; } .track-popup-sources a:hover { text-decoration: underline; } /* ET-011: кнопка «Скачать GPX» в popup публичного трека (REQ-NF-04) */ .track-popup-actions { margin-top: 8px; display: flex; gap: 8px; } .track-popup-download-btn { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 6px; cursor: pointer; background: var(--accent, #ff8c1a); color: #fff; padding: 0; transition: opacity 0.15s ease; } .track-popup-download-btn:hover { opacity: 0.9; } .track-popup-download-btn:focus { outline: 2px solid var(--accent, #ff8c1a); outline-offset: 2px; } .track-popup-download-btn svg { width: 18px; height: 18px; } .track-popup-download-btn.is-loading { opacity: 0.6; pointer-events: none; }