/* Dark ops console.
   The five semantic colours below mirror VERDICTS and mapLayers in
   web/static/js/main.js - that file stays the source of truth for what a
   marker is painted, these are for chrome that has to agree with it. */
:root {
  --nav-0: #0a1220;
  --nav-1: #101b2c;
  --nav-2: #17253a;
  --line:  #23364f;
  --ink:   #dbe6f5;
  --muted: #8297b8;
  --brass: #e2a33f;

  --c-dark:  #ef4444;
  --c-track: #22c55e;
  --c-fa:    #9ca3af;
  --c-ping:  #ff3388;
  --c-pred:  #00ffff;

  --ui: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

body {
  margin: 0;
  background: var(--nav-0);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* Otherwise the native datetime picker and select drop-downs render as white
   widgets punched into the dark page. */
input, select, button, textarea {
  color-scheme: dark;
}

/* ── loading overlay ──────────────────────────────────────────── */
.loading-overlay {
  position: fixed;
  inset: 0;
  background: rgba(7, 13, 23, 0.78);
  backdrop-filter: blur(2px);
  z-index: 9999;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  pointer-events: all;
}

.loading-overlay.active {
  display: flex;
}

.spinner {
  border: 8px solid var(--line);
  border-top: 8px solid var(--brass);
  border-radius: 50%;
  width: 70px;
  height: 70px;
  animation: spin 1s linear infinite;
}

/* A fetch is a Sentinel download plus YOLO plus fusion - a bare spinner with
   no caption reads as a hang. */
.loading-caption {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  color: var(--muted);
}

@keyframes spin {
  0%   { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

/* ── app bar ──────────────────────────────────────────────────── */
.appbar {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 0 1rem;
  height: 46px;
  background: linear-gradient(180deg, #0d1626, #0a1220);
  border-bottom: 1px solid var(--line);
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--mono);
  font-size: 0.74rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 700;
  white-space: nowrap;
}

.brand i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--c-dark);
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.18);
  flex: none;
}

.appnav {
  display: flex;
  gap: 0.15rem;
  overflow-x: auto;
}

.appnav a {
  padding: 0.3rem 0.7rem;
  border-radius: 6px;
  font-size: 0.82rem;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
}

.appnav a:hover {
  color: var(--ink);
  background: var(--nav-2);
}

.appnav a[aria-current="page"] {
  color: var(--brass);
  background: rgba(226, 163, 63, 0.12);
  font-weight: 600;
}

.page-label {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

/* ── shell ────────────────────────────────────────────────────── */
.shell {
  display: grid;
  grid-template-areas: "rail map" "foot foot";
  grid-template-columns: 300px 1fr;
  grid-template-rows: 1fr auto;
  height: calc(100dvh - 46px);
}

.rail {
  grid-area: rail;
  border-right: 1px solid var(--line);
  background: #0c1523;
  padding: 0.85rem;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  overflow-y: auto;
  min-height: 0;
}

.rail-divider {
  height: 1px;
  background: var(--line);
  flex: none;
}

.mapwrap {
  grid-area: map;
  position: relative;
  overflow: hidden;
  background: #050b13;
  min-width: 0;
}

#map {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  background: #050b13;
}

/* ── controls ─────────────────────────────────────────────────── */
.step {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.step > label,
.panel-head,
.strip-legend {
  font-family: var(--mono);
  font-size: 0.63rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0;
}

.step > label b {
  color: var(--brass);
  font-weight: 700;
}

.btn-row {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

button,
.btn {
  font: inherit;
  font-size: 0.83rem;
  padding: 0.42rem 0.8rem;
  border-radius: 6px;
  border: 1px solid transparent;
  cursor: pointer;
  white-space: nowrap;
  background: var(--brass);
  color: #1a1204;
  font-weight: 650;
}

button:hover,
.btn-primary:hover {
  background: #f0b458;
}

.btn-secondary {
  background: var(--nav-2);
  color: var(--ink);
  border-color: var(--line);
  font-weight: 400;
}

.btn-secondary:hover {
  background: #1e2f49;
}

.btn-ghost {
  background: transparent;
  color: var(--muted);
  border-color: var(--line);
  font-weight: 400;
}

.btn-ghost:hover {
  color: var(--ink);
  background: transparent;
}

button:focus-visible,
.btn:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 2px;
}

button[disabled],
.btn[disabled] {
  opacity: 0.3;
  cursor: not-allowed;
}

input, select {
  font: inherit;
  font-family: var(--mono);
  font-size: 0.82rem;
  color: var(--ink);
  background: #0b1524;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.42rem 0.6rem;
}

.field {
  width: 100%;
}

label {
  font-weight: 600;
}

.hint {
  font-size: 0.72rem;
  color: var(--muted);
}

/* The drawn area, echoed back so it is clear what will be searched. */
.aoi-chip {
  font-family: var(--mono);
  font-size: 0.74rem;
  line-height: 1.45;
  background: #0b1524;
  border: 1px dashed rgba(226, 163, 63, 0.45);
  border-radius: 6px;
  padding: 0.35rem 0.55rem;
  font-variant-numeric: tabular-nums;
}

.aoi-chip.unset {
  color: var(--muted);
  border-color: var(--line);
}

/* ── status banner ────────────────────────────────────────────── */
.banner {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  font-size: 0.8rem;
  line-height: 1.45;
  padding: 0.5rem 0.7rem;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--nav-1);
  color: var(--muted);
}

.banner b {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  flex: none;
  padding-top: 0.1rem;
}

.banner.info b {
  color: var(--brass);
}

.banner.error {
  border-color: rgba(239, 68, 68, 0.5);
  background: rgba(239, 68, 68, 0.10);
  color: #fbd5d5;
}

.banner.error b {
  color: var(--c-dark);
}

/* ── side panels ──────────────────────────────────────────────── */
#sidepanel {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  min-height: 0;
  flex: 1;
}

.panel {
  background: var(--nav-1);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.7rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  min-height: 0;
}

.panel-head {
  justify-content: space-between;
}

.count {
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: var(--nav-2);
  border-radius: 999px;
  padding: 0.05rem 0.45rem;
  letter-spacing: 0.04em;
}

.count.alert {
  background: rgba(239, 68, 68, 0.16);
  color: #fca5a5;
}

.empty,
.panel-empty {
  font-size: 0.8rem;
  color: var(--muted);
  line-height: 1.5;
  margin: 0;
  padding: 0.4rem 0;
}

/* ── detections (built by renderDarkShips in main.js) ─────────── */
.dark-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  overflow-y: auto;
  min-height: 0;
}

.det {
  border: 1px solid rgba(239, 68, 68, 0.35);
  border-left: 3px solid var(--c-dark);
  background: rgba(239, 68, 68, 0.10);
  border-radius: 6px;
  padding: 0.5rem 0.55rem;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  cursor: pointer;
}

.det:hover {
  background: rgba(239, 68, 68, 0.17);
}

.det-head {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  font-family: var(--mono);
  font-size: 0.76rem;
  font-variant-numeric: tabular-nums;
}

.det-rank {
  color: #fca5a5;
  font-weight: 700;
}

.det-score {
  margin-left: auto;
  color: #fca5a5;
  font-weight: 700;
  font-size: 0.85rem;
}

.det small {
  font-family: var(--mono);
  font-size: 0.68rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* P(H_D) at a glance - the number is already there, this is for scanning. */
.bar {
  height: 4px;
  background: rgba(239, 68, 68, 0.22);
  border-radius: 999px;
  overflow: hidden;
}

.bar > i {
  display: block;
  height: 100%;
  background: var(--c-dark);
}

/* Explained by AIS: same row, green, so the list is every scored detection
   rather than only the alarming ones. */
.det.matched {
  border-color: rgba(34, 197, 94, 0.3);
  border-left-color: var(--c-track);
  background: rgba(34, 197, 94, 0.08);
}

.det.matched:hover      { background: rgba(34, 197, 94, 0.14); }
.det.matched .det-rank,
.det.matched .det-score { color: #86efac; }
.det.matched .bar       { background: rgba(34, 197, 94, 0.2); }
.det.matched .bar > i   { background: var(--c-track); }

.det.fa {
  border-color: var(--line);
  border-left-color: var(--c-fa);
  background: rgba(156, 163, 175, 0.08);
}

.det.fa:hover      { background: rgba(156, 163, 175, 0.14); }
.det.fa .det-rank,
.det.fa .det-score { color: #d1d5db; }
.det.fa .bar       { background: rgba(156, 163, 175, 0.2); }
.det.fa .bar > i   { background: var(--c-fa); }

/* ── scene list in the rail ───────────────────────────────────── */
.scenes,
.catalogue-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow-y: auto;
  min-height: 0;
}

.scene-row {
  font: inherit;
  text-align: left;
  background: transparent;
  border: 0;
  border-left: 2px solid transparent;
  border-radius: 0 5px 5px 0;
  padding: 0.35rem 0.45rem;
  cursor: pointer;
  display: grid;
  grid-template-columns: 10px 1fr auto;
  grid-template-areas: "state when badges" ". meta meta";
  align-items: center;
  gap: 0.15rem 0.45rem;
  color: var(--muted);
  font-weight: 400;
  width: 100%;
}

.scene-row:hover {
  background: var(--nav-2);
  color: var(--ink);
}

.scene-row[aria-current="true"] {
  background: rgba(226, 163, 63, 0.10);
  border-left-color: var(--brass);
  color: var(--ink);
}

/* Imagery exists but its AIS hour is not on disk - listed so the gap is
   legible, but there is nothing to load. */
.scene-row[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  background: transparent;
}

.scene-state {
  grid-area: state;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  border: 1.5px solid var(--muted);
}

.scene-row.fetched .scene-state {
  background: var(--brass);
  border-color: var(--brass);
}

.scene-row[aria-current="true"] .scene-state {
  box-shadow: 0 0 0 3px rgba(226, 163, 63, 0.25);
}

.scene-when {
  grid-area: when;
  font-family: var(--mono);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.scene-row[aria-current="true"] .scene-when {
  color: var(--brass);
  font-weight: 600;
}

.scene-badges {
  grid-area: badges;
  display: flex;
  gap: 0.25rem;
  align-items: center;
}

.badge {
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.06em;
  padding: 0.02rem 0.3rem;
  border-radius: 3px;
  border: 1px solid var(--line);
  color: var(--muted);
  white-space: nowrap;
}

.badge.dark {
  border-color: rgba(239, 68, 68, 0.5);
  background: rgba(239, 68, 68, 0.14);
  color: #fca5a5;
  font-weight: 700;
}

.scene-meta {
  grid-area: meta;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--mono);
  font-size: 0.63rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* Coverage of the drawn box, as a plain 0-100% fill: the search lists every
   scene that overlaps the box at all, so how much of it a scene covers is the
   user's call to make. */
.cover {
  flex: 1;
  height: 3px;
  background: var(--nav-2);
  border-radius: 999px;
  overflow: hidden;
  min-width: 30px;
}

.cover > i {
  display: block;
  height: 100%;
  background: #4a7fb5;
}

/* ── planned Sentinel-1 passes (built by renderPasses in main.js) ─
   Same row geometry as .scene-row: the rail should read as one list of times.
   The difference that matters is that these have not happened yet, so the
   state dot is hollow brass rather than the archive's filled/empty pair, and
   fills in only once a pass is inside 24h. */
.pass-row .scene-state {
  border-color: var(--brass);
  opacity: 0.65;
}

.pass-row.soon .scene-state {
  background: var(--brass);
  opacity: 1;
}

.pass-row.soon .scene-when {
  color: var(--brass);
}

.pass-row .cover > i {
  background: var(--brass);
}

/* ── footer: three forms, chosen by how many scenes came back ─── */
.footbar {
  grid-area: foot;
  background: #0d1626;
  border-top: 1px solid var(--line);
  padding: 0.5rem 0.9rem 0.6rem;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  min-height: 0;
}

.footbar.hidden {
  display: none;
}

/* /live and /vis put prose here rather than a scene picker. */
#output {
  flex: 1;
  font-size: 0.8rem;
  color: var(--muted);
  min-width: 0;
}

.foot-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}

.foot-meta {
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* form 1: a single scene - no axis, no stepping */
.solo {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.1rem;
  padding: 0.15rem 0;
}

.solo .when {
  font-family: var(--mono);
  font-size: 0.85rem;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* form 2: 2-4 scenes - chips, evenly spaced, no time axis */
.chips {
  display: flex;
  gap: 0.35rem;
  flex-wrap: wrap;
  justify-content: center;
}

.chip {
  font: inherit;
  font-family: var(--mono);
  font-size: 0.74rem;
  font-variant-numeric: tabular-nums;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.6rem;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: #0b1524;
  color: var(--muted);
  cursor: pointer;
  font-weight: 400;
}

.chip:hover {
  color: var(--ink);
  border-color: #34496b;
  background: #0b1524;
}

.chip[aria-current="true"] {
  color: var(--brass);
  border-color: var(--brass);
  background: rgba(226, 163, 63, 0.12);
  font-weight: 600;
}

.chip .pip {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  border: 1.5px solid var(--muted);
  flex: none;
}

.chip.fetched .pip  { background: var(--brass);  border-color: var(--brass); }
.chip.has-dark .pip { background: var(--c-dark); border-color: var(--c-dark); }

/* form 3: 5+ scenes - the time axis earns its place */
.strip {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 0;
}

.strip-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  font-family: var(--mono);
  font-size: 0.64rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  letter-spacing: 0.06em;
}

.strip-head .now { color: var(--ink); font-size: 0.78rem; }
.strip-head .idx { text-transform: uppercase; letter-spacing: 0.12em; }

.track {
  position: relative;
  height: 26px;
  border-radius: 4px;
  background: linear-gradient(180deg, #0b1524, #0a1220);
  border: 1px solid var(--line);
}

.track .week {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: rgba(255, 255, 255, 0.06);
}

.tick {
  position: absolute;
  top: 4px;
  width: 3px;
  height: 18px;
  margin-left: -1.5px;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: #46608a;
  cursor: pointer;
}

.tick:hover      { background: var(--ink); }
.tick.fetched    { background: var(--brass); opacity: 0.75; }
.tick.has-dark   { background: var(--c-dark); }
.tick.no-ais     { background: #2c3d57; cursor: not-allowed; }

.tick[aria-current="true"] {
  background: var(--brass);
  opacity: 1;
  width: 5px;
  margin-left: -2.5px;
  height: 24px;
  top: 1px;
  box-shadow: 0 0 0 2px rgba(226, 163, 63, 0.3);
}

.tick:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 2px;
}

.strip-legend {
  gap: 0.9rem;
  flex-wrap: wrap;
}

.strip-legend span {
  display: flex;
  align-items: center;
  gap: 0.3rem;
}

.strip-legend i {
  width: 8px;
  height: 8px;
  border-radius: 2px;
  display: inline-block;
}

/* ── imagery ──────────────────────────────────────────────────── */
.grayscale-satellite {
  filter: grayscale(100%) contrast(120%);
}

/* The land mask must not pick up the grayscale filter above - being red is the
   whole point of it. */
.land-mask-overlay {
  mix-blend-mode: multiply;
  pointer-events: none;
}

/* ── leaflet chrome ───────────────────────────────────────────── */
/* Every one of these defaults to a white background, which on a dark basemap
   reads as holes punched in the map. */
.leaflet-container {
  background: #050b13;
  font-family: var(--ui);
}

.leaflet-bar,
.leaflet-bar a,
.leaflet-draw-toolbar a,
.leaflet-control-zoom a {
  background-color: rgba(13, 22, 38, 0.92);
  color: var(--ink);
  border-color: var(--line);
}

.leaflet-bar a:hover,
.leaflet-draw-toolbar a:hover,
.leaflet-control-zoom a:hover {
  background-color: var(--nav-2);
  color: var(--ink);
}

.leaflet-bar a.leaflet-disabled {
  background-color: rgba(13, 22, 38, 0.6);
  color: #46608a;
}

/* leaflet-draw ships black sprite icons; invert so they read on dark. */
.leaflet-draw-toolbar a {
  filter: invert(1) hue-rotate(180deg) brightness(1.4);
}

.leaflet-draw-actions a {
  background: var(--nav-2);
  color: var(--ink);
  border-left-color: var(--line);
}

.leaflet-draw-actions a:hover {
  background: #1e2f49;
}

.leaflet-draw-tooltip {
  background: rgba(13, 22, 38, 0.95);
  border-color: var(--line);
  color: var(--ink);
}

.leaflet-control-attribution {
  background: rgba(7, 13, 23, 0.8) !important;
  color: #5f7395;
  font-family: var(--mono);
  font-size: 0.6rem;
}

.leaflet-control-attribution a {
  color: var(--muted);
}

.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
  background: #101b2c;
  color: var(--ink);
  box-shadow: 0 3px 14px rgba(0, 0, 0, 0.5);
}

.leaflet-popup-content-wrapper {
  border: 1px solid var(--line);
  border-radius: 7px;
}

.leaflet-popup-content {
  font-size: 0.78rem;
  line-height: 1.5;
}

.leaflet-container a.leaflet-popup-close-button {
  color: var(--muted);
}

.leaflet-container a.leaflet-popup-close-button:hover {
  color: var(--ink);
}

/* One toggle per marker class the scene draws - see mapLayers in main.js */
.map-layers-control {
  background: rgba(13, 22, 38, 0.92);
  border: 1px solid var(--line);
  border-radius: 7px;
  padding: 0.5rem 0.6rem;
  font-size: 0.75rem;
  line-height: 1.4;
  backdrop-filter: blur(6px);
  max-width: 15rem;
  box-shadow: 0 3px 14px rgba(0, 0, 0, 0.4);
}

.map-layers-control strong {
  display: block;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
  margin-bottom: 0.35rem;
}

.map-layers-control label {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
  font-weight: 600;
}

.map-layers-control input {
  accent-color: var(--brass);
  margin: 0;
}

.map-layers-control small {
  display: block;
  color: var(--muted);
  font-weight: 400;
  font-size: 0.68rem;
  margin: 0 0 0.3rem 1.55rem;
}

/* Empty until a scene is loaded - collapse it so the rows don't drift apart */
.map-layers-control small:empty {
  margin-bottom: 0;
}

.layer-swatch {
  display: inline-block;
  width: 11px;
  height: 11px;
  border-radius: 2px;
  border: 1px solid rgba(255, 255, 255, 0.35);
  flex: none;
}

/* ── live AIS status pills (/live) ────────────────────────────── */
.status-badge {
  display: inline-block;
  padding: 0.25rem 0.7rem;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.78rem;
  color: white;
}

.status-connecting { background: #b45309; }
.status-live       { background: #15803d; }
.status-down       { background: #b91c1c; }

/* Shared by /live and /vis, whose controls are a stack of labelled fields. */
.date-group {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.8rem;
}

.date-group label {
  font-family: var(--mono);
  font-size: 0.63rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}

.MMSI {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8rem;
}

/* ── upstream AIS outage notice (js/ais_status.js) ────────────── */
/* Floated over the map rather than inserted into the layout: .shell sizes
   itself against the viewport, so a banner in the flow would push the map off
   the bottom of every page. Above leaflet's panes (max ~700), below the
   loading overlay (9999) - a download in progress still owns the screen. */
.ais-status-card {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 8000;
  width: min(24rem, calc(100vw - 2rem));
  max-height: min(70vh, 34rem);
  overflow-y: auto;
  background: var(--nav-1);
  border: 1px solid var(--line);
  border-left: 4px solid var(--brass);
  border-radius: 6px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.55);
  font-size: 0.8rem;
  animation: ais-status-in 180ms ease-out;
}

@keyframes ais-status-in {
  from { opacity: 0; transform: translateY(0.5rem); }
  to   { opacity: 1; transform: none; }
}

/* Same distinction the monitor draws: a silent feed is degraded (data may be
   missing), a refused connection is down (there is no data at all). */
.ais-status-card.severity-degraded { border-left-color: var(--brass); }
.ais-status-card.severity-down     { border-left-color: var(--c-dark); }

.ais-status-header {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.7rem 0.8rem 0.5rem;
  border-bottom: 1px solid var(--line);
}

.ais-status-title {
  flex: 1;
  font-weight: 600;
  line-height: 1.35;
}

.ais-status-close {
  background: none;
  border: 0;
  color: var(--muted);
  font-size: 1.15rem;
  line-height: 1;
  padding: 0 0.15rem;
  cursor: pointer;
}

.ais-status-close:hover { color: var(--ink); }

.ais-status-body {
  padding: 0.65rem 0.8rem 0.8rem;
  color: var(--muted);
}

.ais-status-body p {
  margin: 0 0 0.55rem;
}

.ais-status-notes {
  border-left: 2px solid var(--line);
  padding-left: 0.55rem;
  font-style: italic;
}

.ais-status-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.6rem;
  margin: 0.6rem 0 0;
  font-family: var(--mono);
  font-size: 0.68rem;
}

.ais-status-facts dt {
  color: var(--muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.ais-status-facts dd {
  margin: 0;
  color: var(--ink);
}

.ais-status-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin-top: 0.75rem;
}

.ais-status-links a {
  color: var(--brass);
  text-decoration: none;
  font-weight: 600;
}

.ais-status-links a:hover { text-decoration: underline; }

/* ── narrow ───────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .shell {
    grid-template-areas: "rail" "map" "foot";
    grid-template-columns: 1fr;
    grid-template-rows: auto 340px auto;
    height: auto;
    min-height: calc(100dvh - 46px);
  }

  .rail {
    border-right: 0;
    border-bottom: 1px solid var(--line);
    overflow: visible;
  }

  .mapwrap {
    min-height: 340px;
  }

  .footbar {
    flex-wrap: wrap;
  }

  .foot-body {
    flex-basis: 100%;
    order: -1;
  }
}
