/* Cercapila — the bits of the design that utilities can't express.
   Palette mirrors tailwind.config in base.html; see docs/design-spec.md. */

/* Tokens are "R G B" triplets so Tailwind's opacity modifiers work
   (rgb(var(--x) / <alpha-value>)). Dark is the default; the light values are
   picked to clear WCAG AA on every surface they appear on — see
   tests/test_accessibility.py, which computes the ratios. */
:root {
  --bg: 18 21 28;
  --surface: 26 33 43;
  --surface-2: 33 42 51;
  --surface-inset: 27 31 42;
  --border: 35 44 56;
  --accent: 62 230 168;
  --accent-dim: 67 208 156;
  --accent-deep: 19 131 85;
  --accent-bg: 22 57 51;
  --accent-fg: 18 21 28;      /* text on an accent-filled button */
  --warn: 229 192 123;
  --warn-bg: 51 41 26;
  --lime: 163 208 85;
  --text: 232 237 243;
  --muted: 170 180 194;
  --dim: 146 156 170;

  --map-shell: 18 21 28;      /* vignette over the map */
  --map-shell-alpha: 0.34;
  color-scheme: dark;
}

:root[data-theme="light"] {
  --bg: 245 247 250;
  --surface: 255 255 255;
  --surface-2: 236 239 244;
  --surface-inset: 240 243 247;
  --border: 214 220 229;
  --accent: 62 230 168;       /* the button fill stays the brand mint */
  --accent-dim: 10 124 85;    /* ...but accent *text* has to darken */
  --accent-deep: 8 100 68;
  --accent-bg: 220 250 238;
  --accent-fg: 17 24 32;
  --warn: 138 90 0;
  --warn-bg: 253 243 224;
  --lime: 106 158 26;
  --text: 17 24 32;
  --muted: 74 85 102;
  --dim: 93 106 125;

  --map-shell: 245 247 250;
  --map-shell-alpha: 0.16;
  color-scheme: light;
}

/* ── Horizontal chip rail ─────────────────────────────────────────── */
.no-scrollbar {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.no-scrollbar::-webkit-scrollbar { display: none; }

/* ── Radar ────────────────────────────────────────────────────────── */
.radar {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  max-width: 300px;
  margin-inline: auto;
}

.radar__count { font-size: 3rem; }
.radar__caption { font-size: 10px; }

/* A larger dial on desktop — it also sets the height of the map beside it. */
@media (min-width: 1024px) {
  .radar { max-width: 360px; }
  .radar__count { font-size: 3.5rem; }
}

.radar__ring {
  position: absolute;
  inset: 0;
  margin: auto;
  border: 1px solid rgb(var(--accent-dim) / 0.22);
  border-radius: 50%;
}
/* The outermost ring is the search radius itself, so it reads stronger. */
.radar__ring--edge { border-color: rgb(var(--accent-dim) / 0.42); }

/* Distance labels, sitting just inside each ring on the vertical axis. */
.radar__ring-label {
  position: absolute;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 0 5px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 8.5px;
  letter-spacing: 0.08em;
  color: rgb(var(--dim));
  background: rgb(var(--bg));
  border-radius: 4px;
  white-space: nowrap;
  pointer-events: none;
}

/* Zoom buttons under the dial. */
.radar__zoom {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 9999px;
  border: 1px solid rgb(var(--border));
  background: rgb(var(--surface));
  color: rgb(var(--muted));
  transition: color 150ms ease, border-color 150ms ease;
}
.radar__zoom svg { width: 14px; height: 14px; }
.radar__zoom:hover:not(:disabled) {
  color: rgb(var(--accent-dim));
  border-color: rgb(var(--accent-dim) / 0.5);
}
.radar__zoom:disabled { opacity: 0.35; cursor: not-allowed; }
.radar__zoom:focus-visible {
  outline: 2px solid rgb(var(--accent));
  outline-offset: 2px;
}

/* Faint crosshair, so bearings read as bearings. */
.radar__crosshair {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to right, transparent calc(50% - 0.5px), rgb(var(--accent-dim) / 0.16) 50%, transparent calc(50% + 0.5px)),
    linear-gradient(to bottom, transparent calc(50% - 0.5px), rgb(var(--accent-dim) / 0.16) 50%, transparent calc(50% + 0.5px));
  border-radius: 50%;
}

/* The sweeping wedge. */
.radar__sweep {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    rgb(var(--accent-dim) / 0.30) 0deg,
    rgb(var(--accent-dim) / 0.12) 38deg,
    rgb(var(--accent-dim) / 0) 72deg,
    rgb(var(--accent-dim) / 0) 360deg
  );
  animation: radar-sweep 4s linear infinite;
  transform-origin: 50% 50%;
}

@keyframes radar-sweep {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* One station on the radar. */
.radar__dot {
  position: absolute;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: rgb(var(--accent));
  box-shadow: 0 0 0 3px rgb(var(--accent-dim) / 0.16), 0 0 10px rgb(var(--accent-dim) / 0.55);
  transition: transform 160ms ease, box-shadow 160ms ease;
}

/* Raised when its station's card is hovered or focused. */
.radar__dot--active {
  transform: translate(-50%, -50%) scale(1.9);
  z-index: 5;
  box-shadow: 0 0 0 5px rgb(var(--accent-dim) / 0.28), 0 0 18px rgb(var(--accent-dim) / 0.85);
}
.radar__dot--in_use.radar__dot--active,
.radar__dot--offline.radar__dot--active {
  box-shadow: 0 0 0 5px rgb(var(--warn) / 0.22), 0 0 18px rgb(var(--warn) / 0.8);
}
.radar__dot--unknown.radar__dot--active {
  box-shadow: 0 0 0 5px rgb(var(--muted) / 0.2), 0 0 18px rgb(var(--muted) / 0.6);
}

/* The card whose dot is lit gets a matching cue. */
.station-card.is-active {
  border-color: rgb(var(--accent-dim) / 0.4);
}
.radar__dot--in_use,
.radar__dot--offline {
  background: rgb(var(--warn));
  box-shadow: 0 0 0 3px rgb(var(--warn) / 0.14), 0 0 10px rgb(var(--warn) / 0.45);
}
.radar__dot--unknown {
  background: rgb(var(--muted));
  box-shadow: 0 0 0 3px rgb(var(--muted) / 0.12);
}

/* Centre readout sits above the sweep. */
.radar__centre {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

/* ── Live dot in the location chip ────────────────────────────────── */
.pulse-dot {
  position: relative;
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgb(var(--accent));
}
.pulse-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: rgb(var(--accent));
  animation: pulse-ring 2s ease-out infinite;
}
@keyframes pulse-ring {
  0%   { transform: scale(1);   opacity: 0.7; }
  100% { transform: scale(3.2); opacity: 0; }
}

/* ── Route strip on the detail screen ─────────────────────────────── */
.route-line {
  flex: 1;
  height: 2px;
  background-image: linear-gradient(
    to right,
    rgb(var(--dim)) 0 6px,
    transparent 6px 12px
  );
  background-size: 12px 2px;
  background-repeat: repeat-x;
}

@media (min-width: 1024px) {
  /* The controls box has its own surface behind the labels. */
  .radar__ring-label { background: rgb(var(--surface) / 0.4); }
}

/* ── Theme toggle ─────────────────────────────────────────────────── */
/* Show the icon for the theme the button switches *to*, matching its label:
   in dark you see a sun (go light), in light a moon (go dark). */
.theme-icon-dark { display: none; }
.theme-icon-light { display: block; }
:root[data-theme="light"] .theme-icon-light { display: none; }
:root[data-theme="light"] .theme-icon-dark { display: block; }

/* ── Horizontal card shelf (desktop) ─────────────────────────────── */
@media (min-width: 1024px) {
  /* Fade the edges so it reads as scrollable rather than clipped. */
  .card-shelf {
    -webkit-mask-image: linear-gradient(
      to right, transparent 0, #000 18px, #000 calc(100% - 42px), transparent 100%
    );
    mask-image: linear-gradient(
      to right, transparent 0, #000 18px, #000 calc(100% - 42px), transparent 100%
    );
    scroll-padding-inline: 4px;
  }
  .card-shelf:focus-visible {
    outline: 2px solid rgb(var(--accent));
    outline-offset: 4px;
    border-radius: 18px;
  }
}

/* ── "You are here" marker ────────────────────────────────────────── */
/* Magenta deliberately: OSM styles use beige land, green parks, blue water and
   white/amber roads, so nothing on the basemap competes with it — and it can't
   be mistaken for a green station pin. */
.you-marker__dot,
.you-marker__ring,
.you-marker__pulse {
  position: absolute;
  left: 0;
  top: 0;
  border-radius: 50%;
}

.you-marker__dot {
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  background: #ff2d78;
  border: 3px solid #ffffff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45), 0 3px 10px rgba(0, 0, 0, 0.55);
  z-index: 2;
}

/* A steady halo, so it reads as a location even against a busy basemap. */
.you-marker__ring {
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  background: rgba(255, 45, 120, 0.18);
  border: 1.5px solid rgba(255, 45, 120, 0.55);
  z-index: 1;
}

.you-marker__pulse {
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  background: rgba(255, 45, 120, 0.35);
  animation: you-pulse 2.4s ease-out infinite;
  z-index: 0;
}

@keyframes you-pulse {
  0%   { transform: scale(0.55); opacity: 0.85; }
  100% { transform: scale(2.4);  opacity: 0; }
}

/* ── HTMX loading state ───────────────────────────────────────────── */
.htmx-indicator { opacity: 0; transition: opacity 150ms ease; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { opacity: 1; }
.htmx-request .fades-while-loading { opacity: 0.45; transition: opacity 150ms ease; }

/* ── MapLibre, themed to match ────────────────────────────────────── */
/* No filter is applied to the basemap at any setting: the OpenMapTiles styles
   are designed as-is, and filtering was only ever a workaround for raster OSM
   (where inverting to dark hid the road fills). Markers keep their true
   colour with nothing to undo. */
.maplibregl-map { font-family: inherit; background: rgb(var(--surface)); }

/* Softens the join where a light basemap meets the dark shell. Harmless on a
   dark style, so it doesn't need to know which one is active. */
.maplibregl-map::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
  box-shadow: inset 0 0 0 1px rgb(var(--border)),
              inset 0 0 46px rgb(var(--map-shell) / var(--map-shell-alpha));
}

.maplibregl-ctrl-group {
  background: rgb(var(--surface) / 0.94) !important;
  border: 1px solid rgb(var(--border)) !important;
  box-shadow: 0 2px 8px rgb(0 0 0 / 0.18) !important;
}
.maplibregl-ctrl-group button + button { border-top-color: rgb(var(--border)) !important; }
/* MapLibre's control glyphs are dark PNGs — invert them only on a dark chrome. */
.maplibregl-ctrl-group button span { filter: invert(1) brightness(1.7); }
:root[data-theme="light"] .maplibregl-ctrl-group button span { filter: none; }

.maplibregl-ctrl-attrib {
  background: rgb(var(--surface) / 0.86) !important;
  color: rgb(var(--dim)) !important;
  font-size: 10px !important;
}
.maplibregl-ctrl-attrib a { color: rgb(var(--muted)) !important; }
.maplibregl-ctrl-attrib-button { filter: invert(1) brightness(1.7); }
:root[data-theme="light"] .maplibregl-ctrl-attrib-button { filter: none; }

/* MapLibre writes `transform` onto the marker element to position it, so the
   marker element itself is a zero-size anchor and everything visible — and
   everything we scale — lives inside it. */
.map-marker {
  display: block;
  width: 0;
  height: 0;
}

/* Station pin */
.map-pin {
  position: absolute;
  left: 0;
  top: 0;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  border-radius: 50%;
  border: 2px solid rgba(18, 21, 28, 0.85);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.35), 0 2px 6px rgba(0, 0, 0, 0.45);
  cursor: pointer;
  transition: transform 170ms cubic-bezier(0.34, 1.3, 0.64, 1), box-shadow 170ms ease;
  transform-origin: 50% 50%;
}
.map-pin:hover { transform: scale(1.3); }

/* Lifted while its station's card is hovered or focused. */
.map-pin--active {
  transform: scale(2);
  box-shadow: 0 0 0 3px rgb(var(--accent-dim) / 0.35), 0 0 0 1px rgba(18, 21, 28, 0.6),
              0 4px 12px rgba(0, 0, 0, 0.5);
  z-index: 5;
}

/* Popup */
.maplibregl-popup-content {
  background: rgb(var(--surface-2)) !important;
  color: rgb(var(--text)) !important;
  border: 1px solid rgb(var(--border));
  border-radius: 14px !important;
  padding: 12px 14px !important;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.5) !important;
}
.maplibregl-popup-anchor-top .maplibregl-popup-tip { border-bottom-color: rgb(var(--surface-2)) !important; }
.maplibregl-popup-anchor-bottom .maplibregl-popup-tip { border-top-color: rgb(var(--surface-2)) !important; }
.maplibregl-popup-anchor-left .maplibregl-popup-tip { border-right-color: rgb(var(--surface-2)) !important; }
.maplibregl-popup-anchor-right .maplibregl-popup-tip { border-left-color: rgb(var(--surface-2)) !important; }

.map-popup__name {
  display: block;
  font-weight: 700;
  font-size: 13px;
  color: rgb(var(--text));
  text-decoration: none;
}
.map-popup__name:hover { color: rgb(var(--accent)); }
.map-popup__address { color: rgb(var(--dim)); font-size: 11px; margin-top: 2px; }
.map-popup__distance { color: rgb(var(--accent-dim)); font-weight: 600; font-size: 12px; margin-top: 5px; }
.map-popup__link {
  display: inline-block;
  margin-top: 7px;
  font-weight: 700;
  font-size: 11px;
  color: rgb(var(--accent));
  text-decoration: none;
}

@media (prefers-reduced-motion: reduce) {
  .radar__sweep, .pulse-dot::after, .you-marker__pulse { animation: none; }
  .map-pin { transition: none; }
  .radar__dot { transition: none; }
}
