/** * The map's frame and its pins. * * Leaflet ships its own stylesheet for the tiles, controls and popups; this * covers only what the console adds — the container, the divIcon pins and the * empty state — plus the two places leaflet's defaults clash with the console. */ .trail-map { position: relative; z-index: 0; width: 100%; overflow: hidden; border: 1px solid var(--color-border); border-radius: var(--card-radius); background: var(--color-surface-sunken); } .trail-map-canvas { width: 100%; height: 100%; } /* Sits over the tiles rather than replacing them: an empty map still shows the region, so "no positions here" reads as an absence in a real place instead of a component that failed to load. */ .trail-map-empty { position: absolute; inset: auto 0 0 0; z-index: 500; padding: 10px 12px; background: color-mix(in oklab, var(--color-surface) 92%, transparent); border-top: 1px solid var(--color-border); font-size: 12.5px; color: var(--color-ink-3); text-align: center; } /* The divIcon's own box — leaflet gives it a white background and a border by default, which would frame every pin in a small white square. */ .trail-pin-wrap { background: none; border: 0; } .trail-pin { display: block; width: 14px; height: 14px; border-radius: 50%; background: var(--pin, var(--color-brand)); border: 2px solid #fff; box-shadow: 0 1px 4px rgb(15 23 42 / 45%); } /* A place, not an event. Squared off and a touch larger so a shop reads as the thing the round starts from rather than as one more drop on it. */ .trail-pin[data-shape='square'] { width: 15px; height: 15px; border-radius: 3px; } /* A last-known position, not a live one. Hollow, so the difference between "here now" and "here when they last reported" is visible on the map itself and not only in the popup. */ .trail-pin[data-faded='true'] { background: transparent; border-color: var(--pin, var(--color-brand)); border-width: 3px; box-shadow: none; } /* Leaflet's controls and popups default to its own font stack and a blue link colour; both look foreign next to the rest of the console. */ .trail-map .leaflet-container { font: inherit; background: var(--color-surface-sunken); } /* ── Leaflet Modern Popup Card ────────────────────────────────────────────── */ .trail-map .leaflet-popup { margin-bottom: 8px; } .trail-map .leaflet-popup-content-wrapper { padding: 0 !important; border-radius: var(--card-radius) !important; background: var(--card-bg) !important; /* The console's hairline, not a near-miss of it. The shadow STAYS: this one genuinely floats, over a map, which is what a shadow is for. */ border: var(--card-border) !important; box-shadow: 0 16px 36px -4px rgba(15, 23, 42, 0.18), 0 4px 12px rgba(102, 37, 130, 0.1) !important; overflow: hidden !important; } .trail-map .leaflet-popup-content { margin: 0 !important; line-height: 1.4 !important; font-family: inherit !important; color: #1e293b !important; } .trail-map .leaflet-popup-tip-container { overflow: visible; } .trail-map .leaflet-popup-tip { background: #ffffff !important; box-shadow: 0 4px 12px rgba(15, 23, 42, 0.15) !important; } .trail-map .leaflet-popup-close-button { top: 7px !important; right: 7px !important; width: 20px !important; height: 20px !important; display: flex !important; align-items: center !important; justify-content: center !important; border-radius: 50% !important; background: rgba(241, 245, 249, 0.85) !important; color: #64748b !important; font-size: 13px !important; font-weight: 700 !important; text-decoration: none !important; transition: all 0.15s ease !important; z-index: 10 !important; padding: 0 !important; line-height: 1 !important; } .trail-map .leaflet-popup-close-button:hover { background: #fee2e2 !important; color: #ef4444 !important; transform: scale(1.08); } /* Card Content Structure */ .map-popup-card { display: flex; flex-direction: column; min-width: 220px; max-width: 275px; background: #ffffff; } .map-popup-header { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px 7px; background: linear-gradient(135deg, rgba(102, 37, 130, 0.06), rgba(146, 85, 171, 0.03)); border-bottom: 1px solid #f1f5f9; padding-right: 32px; } .map-popup-tag { display: inline-flex; align-items: center; gap: 5px; } .map-popup-badge-icon { font-size: 12px; line-height: 1; } .map-popup-id { font-size: 12.5px; font-weight: 800; color: #662582; letter-spacing: -0.01em; } .map-popup-step { display: inline-flex; align-items: center; padding: 2px 7px; border-radius: 999px; background: #662582; color: #ffffff; font-size: 9.5px; font-weight: 800; letter-spacing: 0.02em; } .map-popup-body { padding: 10px 12px 8px; display: flex; flex-direction: column; gap: 6px; } .map-popup-customer-row { display: flex; align-items: flex-start; gap: 8px; } .map-popup-avatar { width: 24px; height: 24px; border-radius: 50%; background: rgba(102, 37, 130, 0.1); color: #662582; font-weight: 800; font-size: 11px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .map-popup-cust-details { display: flex; flex-direction: column; min-width: 0; } .map-popup-customer { font-size: 13px; font-weight: 700; color: #0f172a; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .map-popup-subtitle { font-size: 12px; font-weight: 700; color: #334155; } .map-popup-address { font-size: 11px; color: #64748b; line-height: 1.35; white-space: normal; word-break: break-word; } .map-popup-address-box { display: flex; align-items: flex-start; gap: 6px; background: #f8fafc; padding: 6px 9px; border-radius: 8px; border: 1px solid #e2e8f0; font-size: 11px; color: #334155; line-height: 1.35; } .map-popup-status-bar { display: flex; align-items: center; margin-top: 2px; } .map-popup-status-pill { display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px; border-radius: 999px; background: color-mix(in srgb, var(--pill-color, #662582) 10%, #ffffff); border: 1px solid color-mix(in srgb, var(--pill-color, #662582) 25%, transparent); } .map-popup-status-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--pill-color, #662582); } .map-popup-status-text { font-size: 11px; font-weight: 700; color: var(--pill-color, #662582); text-transform: capitalize; } .map-popup-time { font-size: 10px; font-weight: 600; color: #64748b; } .map-popup-footer { display: flex; align-items: center; justify-content: space-between; padding: 7px 12px 8px; background: #f8fafc; border-top: 1px solid #f1f5f9; } .map-popup-rider { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 600; color: #334155; } .map-popup-rider-icon { font-size: 12px; } .map-popup-amount { font-size: 12.5px; font-weight: 800; color: #047857; background: rgba(16, 185, 129, 0.1); padding: 2px 7px; border-radius: 6px; letter-spacing: -0.01em; } .map-popup-multi-list { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; padding: 4px 6px; background: #f8fafc; border-radius: 6px; border: 1px solid #e2e8f0; } .map-popup-item-row { display: flex; align-items: center; justify-content: space-between; font-size: 10.5px; } .map-popup-item-id { font-weight: 700; color: #662582; } .map-popup-item-status { font-weight: 600; color: #64748b; text-transform: capitalize; } .map-popup-item-more { font-size: 10px; font-weight: 700; color: #64748b; text-align: center; padding-top: 2px; } .map-popup-line { font-size: 12px; color: #334155; margin-bottom: 2px; } .trail-map .leaflet-control-attribution { font-size: 10px; background: color-mix(in oklab, var(--color-surface) 85%, transparent); } .trail-map .leaflet-control-attribution a { color: var(--color-ink-3); } /* A numbered pin carries the stop's place in the round. Bigger than a plain dot because two digits have to stay legible over map detail, and the white ring is what keeps them readable against a dark tile. */ .trail-pin[data-numbered='true'] { display: grid; place-items: center; width: 20px; height: 20px; font-size: 10.5px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1; color: #fff; text-shadow: 0 1px 1px rgb(15 23 42 / 45%); } /* Another round is focused. Faded rather than hidden — a neighbouring rider's stops are still context, and hiding them makes two overlapping rounds impossible to compare. */ .trail-pin[data-muted='true'] { opacity: 0.3; } /* The round's first stop. Ringed rather than recoloured, so it keeps its own status colour while still reading as the start. */ .trail-pin[data-start='true'] { box-shadow: 0 0 0 2px var(--pin, var(--color-brand)), 0 1px 4px rgb(15 23 42 / 45%); }