:root {
  --bg: #0b0f14;
  --panel: #141b24;
  --panel-2: #1b2431;
  --line: #263140;
  --text: #e6edf5;
  --muted: #8b9bb0;
  --accent: #38bdf8;

  --c-bidir: #22c55e;
  --c-disc: #06b6d4;
  --c-tx: #f97316;
  --c-rx: #a855f7;
  --c-dead: #94a3b8;
  --c-drop: #ef4444;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font: 13px/1.45 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

#map { position: absolute; inset: 0; }

/* Shown in place of the canvas when WebGL is unavailable. Centred and muted:
   it explains a blank map instead of leaving the user to guess. */
.map-unavailable {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 24px;
  text-align: center;
  color: var(--muted);
  font: 13px/1.5 ui-sans-serif, system-ui, sans-serif;
  background: var(--bg, #0b0f14);
}

#sidebar {
  position: absolute;
  top: 12px;
  left: 12px;
  bottom: 12px;
  width: 268px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  overflow-y: auto;
  background: color-mix(in srgb, var(--panel) 92%, transparent);
  backdrop-filter: blur(12px);
  border: 1px solid var(--line);
  border-radius: 10px;
  z-index: 5;
}

#sidebar header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

#sidebar h1 {
  margin: 0;
  font-size: 16px;
  letter-spacing: 0.02em;
}

#sidebar h2 {
  margin: 0 0 6px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

/* The bar across the top of the map. It sits above the map and the sidebar, and
   holds only the observer link, so the link is in the first place anyone looks
   rather than buried among map controls. */
#topbar {
  position: absolute;
  /* Clear of the sidebar, which is 268 px wide plus a 12 px margin. */
  top: 12px;
  left: 292px;
  right: 12px;
  z-index: 7;
  display: flex;
  justify-content: flex-start;
  pointer-events: none; /* the bar must not swallow map drags */
}

.top-link {
  display: inline-flex;
  align-items: baseline;
  gap: 9px;
  padding: 7px 14px;
  pointer-events: auto;
  color: var(--text);
  background: color-mix(in srgb, var(--panel) 94%, transparent);
  backdrop-filter: blur(12px);
  border: 1px solid var(--line);
  border-radius: 999px;
  font: inherit;
  font-weight: 600;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
  cursor: pointer;
}

.top-link:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.top-link-hint {
  font-size: 10px;
  font-weight: 400;
  color: var(--muted);
}

.top-link:hover .top-link-hint { color: inherit; }

.panel {
  padding: 9px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 8px;
}

label {
  display: block;
  margin: 6px 0 2px;
  font-size: 11px;
  color: var(--muted);
}

label.check {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 5px 0;
  font-size: 12px;
  color: var(--text);
  cursor: pointer;
}

select {
  width: 100%;
  padding: 5px 7px;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  font: inherit;
}

button {
  width: 100%;
  margin-top: 8px;
  padding: 6px 8px;
  color: var(--text);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  font: inherit;
  cursor: pointer;
}

button:hover { border-color: var(--accent); }

/* A secondary action next to a primary one: same hit area, less weight, so
   Reset view does not read as the thing to press. */
button.ghost {
  margin-top: 6px;
  color: var(--muted);
  background: transparent;
}

button.ghost:hover { color: var(--text); }

#repeater-filter .filter-note {
  margin: 0;
  font-size: 11px;
  line-height: 1.45;
  color: var(--muted);
}

#repeater-filter .empty-note {
  margin-top: 6px;
  padding-left: 8px;
  border-left: 2px solid var(--line);
}

#repeater-filter.loading .filter-note { opacity: 0.6; }

#repeater-filter strong { color: var(--text); }

.to-client {
  display: block;
  margin-top: 8px;
  padding: 6px 8px;
  text-align: center;
  color: var(--text);
  text-decoration: none;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
}

.to-client:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* The admin link sits under the client one and is deliberately quieter: it is
   used by the operator, not by every visitor of the map. */
.to-admin {
  margin-top: 6px;
  color: var(--muted);
  font-size: 11px;
}

.pill {
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: #16351f;
  color: #6ee7a0;
  border: 1px solid #245c34;
}

.pill.bad {
  background: #3a1a1a;
  color: #fca5a5;
  border-color: #622727;
}

/* Neutral by default: a slot count is information, not an alarm. Only a full
   zone turns it red, because that is when the next node cannot transmit. */
.pill.slots {
  background: #1a2233;
  color: #a8c0e8;
  border-color: #2b3d5c;
  font-variant-numeric: tabular-nums;
}

.pill.slots.full {
  background: #3a1a1a;
  color: #fca5a5;
  border-color: #622727;
}

.types {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
}

.types .check { margin: 2px 0; font-size: 11px; }

.swatch {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  flex: 0 0 auto;
  border: 1px solid rgba(255, 255, 255, 0.25);
}

.stats { margin: 0; }
.stats div {
  display: flex;
  justify-content: space-between;
  padding: 2px 0;
  border-bottom: 1px dashed var(--line);
}
.stats div:last-child { border-bottom: 0; }
.stats dt { color: var(--muted); font-size: 11px; }
.stats dd { margin: 0; font-variant-numeric: tabular-nums; }

#sidebar footer {
  margin-top: auto;
  color: var(--muted);
  font-size: 10px;
  line-height: 1.4;
}

.detail {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 300px;
  max-height: calc(100% - 24px);
  overflow-y: auto;
  padding: 12px;
  background: color-mix(in srgb, var(--panel) 96%, transparent);
  border: 1px solid var(--line);
  border-radius: 10px;
  z-index: 6;
}

.detail.hidden { display: none; }

.detail h2 {
  margin: 0 0 8px;
  font-size: 13px;
}

#detail-close {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 24px;
  height: 24px;
  margin: 0;
  padding: 0;
  line-height: 1;
  font-size: 16px;
}

.detail table {
  width: 100%;
  border-collapse: collapse;
  font-size: 11px;
}

.detail td {
  padding: 2px 0;
  vertical-align: top;
}

.detail td:first-child { color: var(--muted); padding-right: 8px; }

.detail h3 {
  margin: 12px 0 4px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.maplibregl-popup-content {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 8px;
  font: 12px/1.4 ui-sans-serif, system-ui, sans-serif;
}

.maplibregl-popup-tip { border-top-color: var(--panel) !important; }

/* --- observer dialog ------------------------------------------------------ */

.observers-dialog {
  width: min(420px, calc(100vw - 32px));
  max-height: min(70vh, 560px);
  padding: 14px;
  color: var(--text);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  font: 13px/1.45 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

.observers-dialog::backdrop { background: rgba(3, 7, 12, 0.6); }

.observers-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.observers-head h2 {
  margin: 0;
  font-size: 14px;
}

#observers-close {
  width: 26px;
  height: 26px;
  margin: 0;
  padding: 0;
  flex: 0 0 auto;
  line-height: 1;
  font-size: 17px;
}

.observers-note {
  margin: 8px 0 10px;
  font-size: 11px;
  color: var(--muted);
}

.observers-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-y: auto;
}

.observers-list li {
  padding: 8px 10px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.obs-row-head {
  display: flex;
  align-items: center;
  gap: 7px;
}

.obs-row-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

.obs-row-meta {
  display: block;
  margin-top: 4px;
  font-size: 11px;
  color: var(--muted);
}

.obs-badge {
  flex: 0 0 auto;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 9.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid var(--line);
}

.obs-badge.online { color: #86efac; border-color: #245c34; background: #11251a; }
.obs-badge.stale { color: #fcd34d; border-color: #6b4e13; background: #2a2110; }
.obs-badge.offline { color: #fca5a5; border-color: #622727; background: #2a1414; }
.obs-badge.never { color: #fca5a5; border-color: #622727; background: #2a1414; }

.observers-empty,
.observers-error {
  margin: 10px 0 0;
  font-size: 11px;
  color: var(--muted);
}

.observers-error { color: #fca5a5; }

@media (max-width: 720px) {
  #sidebar {
    top: auto;
    left: 8px;
    right: 8px;
    bottom: 8px;
    width: auto;
    max-height: 46%;
  }
  .detail { top: 8px; left: 8px; right: 8px; width: auto; }
  /* On a phone the sidebar becomes a bottom sheet, so the bar can use the full
     width instead of reserving space for a panel that is no longer up there. */
  #topbar { top: 8px; left: 8px; right: 8px; }
}
