:root {
  --background: #FAFAF7;
  --ink: #1B2A4A;
  --accent: #D4703A;
  --accent-hover: #B75B2A;
  --accent-soft: rgba(212, 112, 58, 0.12);
  --muted: #6B7280;
  --border: #E5E3DD;
  --white: #FFFFFF;
  --success: #1F5136;
  --success-soft: rgba(31, 81, 54, 0.1);
  --danger: #B3271E;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjAwIiBoZWlnaHQ9IjEyMDAiIHZpZXdCb3g9IjAgMCAxNjAwIDEyMDAiPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJza3kiIHgxPSIwIiB5MT0iMCIgeDI9IjAiIHkyPSIxIj4KPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI0VBRjFFQyIvPgo8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNGNkYxRTciLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8cmVjdCB3aWR0aD0iMTYwMCIgaGVpZ2h0PSIxMjAwIiBmaWxsPSJ1cmwoI3NreSkiLz4KPHBhdGggZD0iTSAwIDEyMDAgTCAwIDQ1Mi42IEMgMTAwLjAgNDUyLjYsIDEwMC4wIDQ2Ni40LCAyMDAuMCA0NjYuNCBDIDMwMC4wIDQ2Ni40LCAzMDAuMCA0MjAuMSwgNDAwLjAgNDIwLjEgQyA1MDAuMCA0MjAuMSwgNTAwLjAgMzkwLjEsIDYwMC4wIDM5MC4xIEMgNzAwLjAgMzkwLjEsIDcwMC4wIDQyNi4xLCA4MDAuMCA0MjYuMSBDIDkwMC4wIDQyNi4xLCA5MDAuMCA0NjguNSwgMTAwMC4wIDQ2OC41IEMgMTEwMC4wIDQ2OC41LCAxMTAwLjAgNDQ3LjMsIDEyMDAuMCA0NDcuMyBDIDEzMDAuMCA0NDcuMywgMTMwMC4wIDM5Ny41LCAxNDAwLjAgMzk3LjUgQyAxNTAwLjAgMzk3LjUsIDE1MDAuMCA0MDEuNCwgMTYwMC4wIDQwMS40IEwgMTYwMCAxMjAwIFoiIGZpbGw9IiNCOUM5RDYiIG9wYWNpdHk9IjAuMzUiLz4KPHBhdGggZD0iTSAwIDEyMDAgTCAwIDYxNC4yIEMgMTAwLjAgNjE0LjIsIDEwMC4wIDU0NC41LCAyMDAuMCA1NDQuNSBDIDMwMC4wIDU0NC41LCAzMDAuMCA1MTkuNCwgNDAwLjAgNTE5LjQgQyA1MDAuMCA1MTkuNCwgNTAwLjAgNjExLjIsIDYwMC4wIDYxMS4yIEMgNzAwLjAgNjExLjIsIDcwMC4wIDU1NS41LCA4MDAuMCA1NTUuNSBDIDkwMC4wIDU1NS41LCA5MDAuMCA1MTIuOCwgMTAwMC4wIDUxMi44IEMgMTEwMC4wIDUxMi44LCAxMTAwLjAgNjA2LjEsIDEyMDAuMCA2MDYuMSBDIDEzMDAuMCA2MDYuMSwgMTMwMC4wIDU2Ni42LCAxNDAwLjAgNTY2LjYgQyAxNTAwLjAgNTY2LjYsIDE1MDAuMCA1MDguMSwgMTYwMC4wIDUwOC4xIEwgMTYwMCAxMjAwIFoiIGZpbGw9IiNDOURGQ0IiIG9wYWNpdHk9IjAuNTUiLz4KPHBhdGggZD0iTSAwIDEyMDAgTCAwIDcxMy45IEMgMTAwLjAgNzEzLjksIDEwMC4wIDczNS4xLCAyMDAuMCA3MzUuMSBDIDMwMC4wIDczNS4xLCAzMDAuMCA2MzMuNiwgNDAwLjAgNjMzLjYgQyA1MDAuMCA2MzMuNiwgNTAwLjAgNzY0LjQsIDYwMC4wIDc2NC40IEMgNzAwLjAgNzY0LjQsIDcwMC4wIDY3MC4xLCA4MDAuMCA2NzAuMSBDIDkwMC4wIDY3MC4xLCA5MDAuMCA2ODAuNCwgMTAwMC4wIDY4MC40IEMgMTEwMC4wIDY4MC40LCAxMTAwLjAgNzU5LjIsIDEyMDAuMCA3NTkuMiBDIDEzMDAuMCA3NTkuMiwgMTMwMC4wIDYzMC45LCAxNDAwLjAgNjMwLjkgQyAxNTAwLjAgNjMwLjksIDE1MDAuMCA3NDQuMiwgMTYwMC4wIDc0NC4yIEwgMTYwMCAxMjAwIFoiIGZpbGw9IiNCN0Q2QkEiIG9wYWNpdHk9IjAuNTUiLz4KPHBhdGggZD0iTSAwIDEyMDAgTCAwIDkyMy40IEMgMTAwLjAgOTIzLjQsIDEwMC4wIDc2NS42LCAyMDAuMCA3NjUuNiBDIDMwMC4wIDc2NS42LCAzMDAuMCA5MzEuNCwgNDAwLjAgOTMxLjQgQyA1MDAuMCA5MzEuNCwgNTAwLjAgNzg1LjAsIDYwMC4wIDc4NS4wIEMgNzAwLjAgNzg1LjAsIDcwMC4wIDg4Ny44LCA4MDAuMCA4ODcuOCBDIDkwMC4wIDg4Ny44LCA5MDAuMCA4NDUuNywgMTAwMC4wIDg0NS43IEMgMTEwMC4wIDg0NS43LCAxMTAwLjAgODIwLjIsIDEyMDAuMCA4MjAuMiBDIDEzMDAuMCA4MjAuMiwgMTMwMC4wIDkwOS4xLCAxNDAwLjAgOTA5LjEgQyAxNTAwLjAgOTA5LjEsIDE1MDAuMCA3NzEuNSwgMTYwMC4wIDc3MS41IEwgMTYwMCAxMjAwIFoiIGZpbGw9IiNBM0NCQTgiIG9wYWNpdHk9IjAuNTUiLz4KPHBhdGggZD0iTSAwIDEyMDAgTCAwIDEwODQuNCBDIDEwMC4wIDEwODQuNCwgMTAwLjAgOTM1LjYsIDIwMC4wIDkzNS42IEMgMzAwLjAgOTM1LjYsIDMwMC4wIDEwODQuNCwgNDAwLjAgMTA4NC40IEMgNTAwLjAgMTA4NC40LCA1MDAuMCA5MzUuNiwgNjAwLjAgOTM1LjYgQyA3MDAuMCA5MzUuNiwgNzAwLjAgMTA4NC40LCA4MDAuMCAxMDg0LjQgQyA5MDAuMCAxMDg0LjQsIDkwMC4wIDkzNS42LCAxMDAwLjAgOTM1LjYgQyAxMTAwLjAgOTM1LjYsIDExMDAuMCAxMDg0LjQsIDEyMDAuMCAxMDg0LjQgQyAxMzAwLjAgMTA4NC40LCAxMzAwLjAgOTM1LjYsIDE0MDAuMCA5MzUuNiBDIDE1MDAuMCA5MzUuNiwgMTUwMC4wIDEwODQuNCwgMTYwMC4wIDEwODQuNCBMIDE2MDAgMTIwMCBaIiBmaWxsPSIjOEZCRTk3IiBvcGFjaXR5PSIwLjU1Ii8+Cjwvc3ZnPg==") no-repeat center center fixed;
  background-size: cover;
  color: var(--ink);
  font-family: -apple-system, "Inter", "Segoe UI", sans-serif;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 28px;
  border-bottom: 1px solid var(--border);
  background: var(--white);
  position: sticky;
  top: 0;
  z-index: 5;
  flex-wrap: wrap;
  gap: 14px;
}

.brand { display: flex; align-items: center; gap: 12px; }
.brand-mark {
  width: 40px; height: 40px; border-radius: 10px;
  object-fit: cover; flex: none; display: block;
  image-rendering: -webkit-optimize-contrast;
}
.brand-title { font-weight: 700; font-size: 16px; }
.brand-subtitle { font-size: 12px; color: var(--muted); margin-top: 2px; }

.tabs { display: flex; gap: 6px; background: var(--background); padding: 4px; border-radius: 999px; border: 1px solid var(--border); }
.tab-btn {
  border: none; background: transparent; padding: 8px 18px; border-radius: 999px;
  font-size: 13px; font-weight: 600; color: var(--muted); cursor: pointer;
}
.tab-btn.active { background: var(--ink); color: var(--white); }

#app { max-width: 1100px; margin: 0 auto; padding: 28px; }

.tab-panel { display: none; }
.tab-panel.active { display: block; }

.panel-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; flex-wrap: wrap; gap: 12px; }
.panel-header h1 { font-size: 22px; margin: 0; }

.row { display: flex; align-items: center; flex-wrap: wrap; }
#stop-trail-filter { width: auto; min-width: 160px; }

.btn {
  border: 1px solid var(--border);
  background: var(--white);
  color: var(--ink);
  padding: 9px 16px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.btn:hover { border-color: #D9D3C6; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--white); }
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-danger { color: var(--danger); }
.btn-small { padding: 5px 11px; font-size: 12px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

.map-mode-btn { border-radius: 0; margin-left: -1px; }
.map-mode-btn:first-child { border-radius: 999px 0 0 999px; margin-left: 0; }
.map-mode-btn:last-child { border-radius: 0 999px 999px 0; }
.map-mode-btn.active { background: var(--ink); border-color: var(--ink); color: var(--white); }

/* ---- Visits map toolbar ---- */
.map-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 10px; }
.basemap-btn { border-radius: 0; margin-left: -1px; }
.basemap-btn:first-child { border-radius: 999px 0 0 999px; margin-left: 0; }
.basemap-btn:last-child { border-radius: 0 999px 999px 0; }
.basemap-btn.active { background: var(--ink); border-color: var(--ink); color: var(--white); }
/* Stop names on the map.
   The colour has to follow the background, or one of the two always
   loses: near-black with a white halo is what reads on the pale street
   map (the way printed maps letter their labels), and white with a dark
   halo is what reads over dark aerial photography. The halo is what
   keeps a name legible where it crosses a road, a path or a marker,
   without a solid box hiding more of the map than the name is worth. */
.stop-label {
  font-size: 11.5px; font-weight: 700; white-space: nowrap;
  pointer-events: none;
  color: #10202e;
  text-shadow:
    -1px -1px 0 rgba(255,255,255,0.95),  1px -1px 0 rgba(255,255,255,0.95),
    -1px  1px 0 rgba(255,255,255,0.95),  1px  1px 0 rgba(255,255,255,0.95),
     0 0 4px rgba(255,255,255,0.9),      0 0 8px rgba(255,255,255,0.7);
}
[data-basemap="satellite"] .stop-label {
  color: #fff;
  text-shadow:
    -1px -1px 0 rgba(0,0,0,0.85),  1px -1px 0 rgba(0,0,0,0.85),
    -1px  1px 0 rgba(0,0,0,0.85),  1px  1px 0 rgba(0,0,0,0.85),
     0 0 4px rgba(0,0,0,0.95),     0 0 9px rgba(0,0,0,0.8);
}
/* Leaflet gives permanent tooltips a white box, an arrow and its own text
   colour. leaflet.css loads after this file, so these need the extra
   class to win on specificity — colour included. */
.leaflet-tooltip.stop-label {
  background: none; border: none; box-shadow: none; padding: 0;
  font-family: inherit; font-size: 11.5px; font-weight: 700;
  color: #10202e;
  text-shadow:
    -1px -1px 0 rgba(255,255,255,0.95),  1px -1px 0 rgba(255,255,255,0.95),
    -1px  1px 0 rgba(255,255,255,0.95),  1px  1px 0 rgba(255,255,255,0.95),
     0 0 4px rgba(255,255,255,0.9),      0 0 8px rgba(255,255,255,0.7);
}
[data-basemap="satellite"] .leaflet-tooltip.stop-label {
  color: #fff;
  text-shadow:
    -1px -1px 0 rgba(0,0,0,0.85),  1px -1px 0 rgba(0,0,0,0.85),
    -1px  1px 0 rgba(0,0,0,0.85),  1px  1px 0 rgba(0,0,0,0.85),
     0 0 4px rgba(0,0,0,0.95),     0 0 9px rgba(0,0,0,0.8);
}
.leaflet-tooltip.stop-label::before { display: none; }
/* The 3D marker is a positioned circle; its name sits above it, matching
   the flat map — the code that stops names colliding assumes that. */
.map3d-marker { position: relative; }
.map3d-label {
  position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%);
  margin-bottom: 3px;
}

.map-tilt { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--muted); }
.map-tilt input[type="range"] { width: 120px; accent-color: var(--accent); }
.map-tools-hint { margin: 0; }
/* Fullscreen: the wrapper is what gets expanded, so the toolbar keeps its
   own height and the map stretches into whatever is left. */
#visits-map-wrap:fullscreen { display: flex; flex-direction: column; background: var(--background); }
#visits-map-wrap:fullscreen .map-toolbar { margin: 0; padding: 10px 14px; background: var(--white); border-bottom: 1px solid var(--border); }
#visits-map-wrap:fullscreen #visits-map,
#visits-map-wrap:fullscreen #visits-map-3d { flex: 1; height: auto !important; border-radius: 0 !important; border: none !important; }
@media (max-width: 640px) {
  .map-tools-hint { display: none; }
}

select, input[type=text], input[type=number], input[type=email], input[type=password], input[type=tel],
input[type=date], input[type=datetime-local], textarea {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 9px 11px;
  font-size: 13.5px;
  font-family: inherit;
  color: var(--ink);
  background: var(--white);
  width: 100%;
}
textarea { resize: vertical; min-height: 70px; }
label { display: block; font-size: 12px; font-weight: 600; color: var(--muted); margin-bottom: 5px; margin-top: 14px; }
label:first-child { margin-top: 0; }
.field-row { display: flex; gap: 12px; }
.field-row > div { flex: 1; }
.hint { font-size: 11.5px; color: var(--muted); margin-top: 4px; }

/* Separates the practical-information block in the stop editor from the
   fields above and below it. Without a rule here the markup renders as an
   empty div and the sections run together. */
.section-divider { border-top: 1px solid var(--border); margin: 18px 0 14px; }
/* Some dividers carry a heading ("When it shows"). An empty one is
   unaffected: with no text there is nothing for the padding to push. */
.section-divider:not(:empty) {
  padding-top: 14px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--muted);
}

/* Status of an advisory on the Today screen. The dot carries the same
   information as the "Live"/"Expired" pill beside it — deliberately
   twice, because colour alone is not something everyone can read. */
.status-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 7px;
  vertical-align: middle;
  background: var(--border);
}
.status-live { background: #1c9c62; }
.status-scheduled { background: #c98a12; }
.status-draft { background: var(--muted); }
.status-expired { background: transparent; border: 1.5px solid var(--border); }

.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }
.trail-card {
  border: 1px solid var(--border); border-radius: 16px; background: var(--white); overflow: hidden;
}
.trail-card .thumb { height: 120px; background: var(--border) center/cover no-repeat; position: relative; }
.trail-card .thumb .empty { display:flex; align-items:center; justify-content:center; height:100%; color: var(--muted); font-size: 12px; }
.trail-card .body { padding: 14px; }
.trail-card .name { font-weight: 700; font-size: 16px; }
.trail-card .meta { font-size: 12px; color: var(--muted); margin-top: 4px; }
.trail-card .actions { display: flex; gap: 8px; margin-top: 12px; }

.stop-list { display: flex; flex-direction: column; gap: 8px; }
.stop-row {
  display: flex; align-items: center; gap: 10px 12px; flex-wrap: wrap;
  border: 1px solid var(--border); border-radius: 12px; background: var(--white); padding: 10px 12px;
}
.stop-row .photo-thumb {
  width: 40px; height: 40px; border-radius: 50%; background: var(--background) center/contain no-repeat; flex: none; border: 1px solid var(--border);
}
.stop-row .photo-thumb { border-radius: 8px; background-size: cover; }
.stop-row .info { flex: 1 1 220px; min-width: 0; }
.stop-row .info .name { font-weight: 600; font-size: 14px; }
.stop-row .info .meta { font-size: 11.5px; color: var(--muted); margin-top: 4px; display: flex; flex-wrap: wrap; gap: 6px; }
.pill { display: inline-flex; align-items: center; height: 22px; padding: 0 10px; border-radius: 999px; background: var(--accent-soft); color: var(--accent); font-size: 10.5px; font-weight: 600; white-space: nowrap; }
.pill.warn { background: #FCE9E7; color: var(--danger); }
.pill.ok { background: var(--success-soft); color: var(--success); }
.stop-row .actions { display: flex; gap: 6px; flex: none; margin-left: auto; }

.modal-scrim {
  position: fixed; inset: 0; background: rgba(20,27,43,0.5);
  display: flex; align-items: flex-start; justify-content: center; padding: 40px 16px; overflow-y: auto; z-index: 20;
}
/* Stacks above an already-open modal — see the comment on confirmDialog()
   in app.js for why this needs its own root and z-index. */
.confirm-scrim { z-index: 30; }
.modal {
  background: var(--background); border-radius: 18px; max-width: 560px; width: 100%; padding: 24px; margin-bottom: 40px;
}
.modal h2 { margin: 0 0 4px; font-size: 19px; }
.modal .modal-sub { font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.modal-footer { display: flex; justify-content: flex-end; gap: 10px; margin-top: 22px; }

.fact-row { display: flex; gap: 8px; align-items: center; margin-top: 8px; }
.fact-row select { flex: 0 0 130px; }
.fact-row input { flex: 1; }
.fact-row button { flex: none; }

.place-row {
  display: flex; align-items: center; gap: 10px 12px; flex-wrap: wrap;
  border: 1px solid var(--border); border-radius: 12px; background: var(--white); padding: 10px 12px; margin-top: 8px;
}
.place-row .place-info { flex: 1 1 220px; min-width: 0; display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.place-row .place-name { font-weight: 600; font-size: 13.5px; }
.place-row .actions { display: flex; gap: 6px; flex: none; margin-left: auto; }
.place-form.place-row { align-items: flex-start; }
.place-form select, .place-form input { width: auto; flex: 1 1 140px; }

.upload-row { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
.upload-preview { width: 56px; height: 56px; border-radius: 10px; background: var(--border) center/cover no-repeat; border: 1px solid var(--border); flex: none; }
.upload-preview.round { border-radius: 50%; background-size: contain; }

#toast {
  position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%);
  background: var(--ink); color: var(--white); padding: 10px 18px; border-radius: 999px; font-size: 13px;
  opacity: 0; pointer-events: none; transition: opacity 200ms;
  z-index: 40;
}
#toast.show { opacity: 1; }

.checkbox-row { display: flex; align-items: center; gap: 8px; margin-top: 14px; }
.checkbox-row input { width: auto; }
.checkbox-row label { margin: 0; }

.empty-state { color: var(--muted); font-size: 13px; padding: 30px; text-align: center; border: 1px dashed var(--border); border-radius: 14px; }

.login-screen {
  display: flex; align-items: center; justify-content: center;
  min-height: 100vh; padding: 20px;
}
/*
  The "checking your sign-in" screen. It deliberately fades in only after
  a short delay: when the check is quick — which is the normal case — it
  never becomes visible at all, so a refresh shows no flash of anything.
  When the server is being slow, a calm logo appears instead of a sign-in
  form that's about to disappear.
*/
.boot-screen {
  display: flex; align-items: center; justify-content: center;
  min-height: 100vh; padding: 20px;
  opacity: 0; animation: boot-fade-in .25s ease .4s forwards;
}
.boot-screen img { width: 108px; height: 108px; border-radius: 24px; }
@keyframes boot-fade-in { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .boot-screen { animation-duration: .01s; }
}
.login-card {
  width: 100%; max-width: 360px; background: var(--white);
  border: 1px solid var(--border); border-radius: 18px; padding: 28px;
  text-align: center;
}
.login-card .brand-mark { width: 108px; height: 108px; border-radius: 24px; margin: 0 auto 16px; }
.login-card h1 { font-size: 19px; margin: 0 0 4px; }
.login-card label { text-align: left; }
.login-error { color: var(--danger); font-size: 12.5px; margin-top: 10px; min-height: 16px; }
