/* SAB Portal — The fleet map: the canvas, the row beneath it, Leaflet's own furniture, the
 * grouped boxes, and the small map a detail page carries.
 *
 * What the map may draw is decided in fleet/mapdata.py. This file decides only
 * what the drawing looks like.
 *
 * One of the files listed in layers.css; read that first. Every rule below
 * is in the `app` cascade layer, so it beats Pico without needing to be
 * more specific than Pico. Sizes come from tokens.css and nowhere else. */

@layer app {

/* --- The fleet map ------------------------------------------------------
 *
 * Leaflet draws the dots and the lines; everything a reader sees around them
 * is here. Two things this section is careful about:
 *
 *   - Nothing here is a colour the map's JavaScript also knows. The dots and
 *     the pipes read their colours out of the custom properties above, so a
 *     restyle is one edit in one block and the legend cannot drift from the
 *     lines it explains.
 *   - Leaflet's own controls keep Leaflet's own dark-on-white. They are chrome
 *     sitting over an arbitrary photograph, and theming them to the page makes
 *     them disappear over satellite imagery.
 */

/* No frame around the dashboard's map. The map is the page's first thing and
 * the largest; a border and a shadow around it made it one card among cards,
 * and the eye had to work out which. */
/* The map on the overview is a panel in the lower row, sized by
 * `.sab-overview-lower` — square beside the companies, and as wide as the
 * page under them when there is no room to be beside anything. */

.sab-map-canvas {
  width: 100%;
  height: 30rem;
  border-radius: var(--sab-radius);
  background: var(--sab-quiet-bg);
}

/* What is left when the fleet cannot be fetched: a sentence, in the space the
 * map would have taken. An empty map would look like a fleet with nothing in
 * it — a confident wrong answer, which is the one thing this portal must not
 * give. */
.sab-map-failed {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Both of these, because the two maps size themselves differently — one by
   * height, one by aspect ratio — and a sentence is neither of those shapes. */
  height: auto;
  aspect-ratio: auto;
  min-height: 6rem;
  padding: var(--sab-gap-loose);
  color: var(--pico-muted-color);
  font-size: var(--sab-text-body);
  border: var(--sab-hairline) solid var(--sab-rule);
}

/* --- The one row under the map -----------------------------------------
 *
 * What a colour means and what a line means, on one line, under the picture
 * they explain. It is the only explanation of four line styles, so it is
 * written by hand and checked against the drawing code by eye.
 *
 * Everything in it carries words. Colour is never the only signal. */

.sab-map-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sab-gap-tight) var(--sab-gap-loose);
  font-size: var(--sab-text-meta);
  color: var(--pico-muted-color);
  margin: var(--sab-gap) 0 0;
}

.sab-map-key {
  display: inline-flex;
  align-items: center;
  gap: var(--sab-gap-tight);
  white-space: nowrap;
}

.sab-map-key::before {
  content: "";
  width: 1.1rem;
  height: 3px;
  border-radius: 2px;
  background: var(--sab-map-forward);
}

.sab-map-key-return::before {
  background: var(--sab-map-return);
}

.sab-map-key-trench::before {
  height: 7px;
  background: var(--sab-map-trench);
  border: 1px solid var(--sab-map-trench-edge);
}

/* A dashed rule, drawn the way the map draws a pipe nobody has measured. */
.sab-map-key-provisional::before {
  height: 0;
  background: none;
  border-top: 2px dashed var(--sab-map-provisional);
  opacity: 0.7;
}

/* --- Leaflet's own furniture -------------------------------------------
 *
 * Leaflet ships square grey boxes with a hairline border. They are legible and
 * they look like a widget dropped on the page, which on a page this plain is
 * the only thing on screen that looks borrowed.
 *
 * So they are restyled — but restyled to stay *opaque*. These controls sit
 * over an arbitrary photograph: a translucent control tinted to the page's
 * surface disappears the moment somebody switches to satellite. Solid
 * background, one hairline, one soft shadow, in both themes.
 */

.leaflet-container {
  font-family: inherit;
  background: var(--sab-quiet-bg);
  border-radius: var(--sab-radius);
}

.leaflet-container a {
  text-decoration: none;
}

.leaflet-container .leaflet-popup-content {
  font-size: var(--sab-text-label);
  line-height: var(--sab-leading);
}

/* Prefixed with the container throughout this block, because Leaflet's own
 * stylesheet is loaded after this one — a page's `head` block comes last — and
 * an override that only matches as tightly as the rule it is overriding loses.
 */
.leaflet-container .leaflet-bar {
  border: var(--sab-hairline) solid var(--sab-rule);
  border-radius: var(--sab-radius);
  box-shadow: 0 1px 3px rgb(9 12 16 / 0.2);
  overflow: hidden;
}

.leaflet-container .leaflet-bar a,
.leaflet-container .leaflet-control-zoom a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  line-height: 1;
  padding: 0;
  margin: 0;
  border: none;
  color: var(--sab-ink);
  background: var(--sab-row);
  font-size: var(--sab-text-base);
  font-weight: var(--sab-weight-medium);
}

.leaflet-container .leaflet-bar a + a {
  border-top: var(--sab-hairline) solid var(--sab-rule);
}

/* Zoom in and zoom out, as two controls rather than one two-storey box.
 *
 * They do opposite things and they are pressed with a thumb on a map that is
 * already moving; welded together, the press that meant `+` lands on `−` and
 * the reader loses the view they were closing in on. A gap is what makes them
 * two targets. Each then carries its own edge and its own shadow, because half
 * a box with nothing round it reads as a broken control. */
.leaflet-container .leaflet-control-zoom.leaflet-bar {
  display: flex;
  flex-direction: column;
  gap: var(--sab-gap-tight);
  border: 0;
  box-shadow: none;
  overflow: visible;
}

.leaflet-container .leaflet-control-zoom.leaflet-bar a {
  border: var(--sab-hairline) solid var(--sab-rule);
  border-radius: var(--sab-radius);
  box-shadow: 0 1px 3px rgb(9 12 16 / 0.2);
}

.leaflet-container .leaflet-bar a:hover,
.leaflet-container .leaflet-bar a:focus-visible {
  background: var(--sab-quiet-bg-hover);
  color: var(--sab-ink);
}

.leaflet-container .leaflet-bar a.leaflet-disabled {
  color: var(--sab-absent);
  background: var(--sab-row);
}

/* The background switcher: three buttons, one of them pressed.
 *
 * Leaflet's own layer control hides its choices behind a hover panel, which is
 * a control most readers never find. Three backgrounds fit on the screen, so
 * they are simply on it, and which one is showing is readable at a glance —
 * pressed carries weight and contrast as well as tint, so it is not a colour
 * doing the work alone. */
.sab-map-switch {
  display: flex;
  border: var(--sab-hairline) solid var(--sab-rule);
  border-radius: var(--sab-radius);
  overflow: hidden;
  box-shadow: 0 1px 3px rgb(9 12 16 / 0.2);
}

.sab-map-switch button {
  width: auto;
  margin: 0;
  padding: 0.3rem 0.7rem;
  border: none;
  border-radius: 0;
  background: var(--sab-row);
  color: var(--sab-ink);
  font-size: var(--sab-text-small);
  font-weight: var(--sab-weight-medium);
  line-height: 1.2;
  white-space: nowrap;
}

.sab-map-switch button + button {
  border-inline-start: var(--sab-hairline) solid var(--sab-rule);
}

.sab-map-switch button:hover {
  background: var(--sab-quiet-bg-hover);
}

.sab-map-switch button[aria-pressed="true"] {
  background: var(--sab-selected-bg);
  color: var(--sab-selected);
  font-weight: var(--sab-weight-strong);
}

/* --- Grouped boxes ------------------------------------------------------
 *
 * A bubble is a DOM element rather than a drawn shape, so it follows the theme
 * without the map being redrawn. Its ring is split by state in proportion —
 * two silent boxes out of twelve read as a red sixth, never as a red bubble —
 * and the count sits in the middle, because a proportion is not a number. */

.sab-map-cluster {
  background: none;
  border: none;
}

.sab-map-bubble {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgb(0 0 0 / 0.35);
}

.sab-map-count {
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(100% - 14px);
  height: calc(100% - 14px);
  border-radius: 50%;
  background: var(--sab-row);
  color: var(--sab-ink);
  font-weight: var(--sab-weight-strong);
  font-variant-numeric: tabular-nums;
  font-size: var(--sab-text-label);
}

/* The permanent name beside a dot in the background-free view. No bubble, no
 * arrow: the label is the only thing on that surface besides the network. */
.leaflet-tooltip.sab-map-tag {
  background: transparent;
  border: none;
  box-shadow: none;
  padding: 0 0 0 2px;
  color: var(--sab-ink);
  font-size: var(--sab-text-micro);
  font-weight: var(--sab-weight-strong);
}

.leaflet-tooltip.sab-map-tag::before {
  display: none;
}

/* On a phone the map competes with the counts below it for the first screen.
 * Shorter, so that what the fleet is is readable without scrolling past a
 * picture of it. */
@media (max-width: 48rem) {
  .sab-map-canvas {
    height: 20rem;
  }
}

/* --- A detail page's own map --------------------------------------------
 *
 * The same dots and the same trench as the fleet map, drawn by the same two
 * files, so nothing here is a colour or a width — those are all above.
 *
 * The left column of the detail row on both detail pages: the picture first,
 * then the words it is a picture of.
 */

.sab-detail-place {
  display: flex;
  flex-direction: column;
  gap: var(--sab-gap-loose);
  /* A grid item's floor is the width of its content, and a Leaflet canvas will
   * happily claim more than the column it is in. */
  min-width: 0;
}

/* On the pipe page the map takes the height the end cards leave, so the left
 * column ends level with the card beside it; the floor keeps a trench legible. */
.sab-detail-map {
  width: 100%;
  flex: 1 1 0;
  min-height: var(--sab-map-least);
  border-radius: var(--sab-radius);
  background: var(--sab-quiet-bg);
}

/* The two boxes are named permanently beside their dots — there are two of
 * them and telling one from the other is what the reader came for, and a name
 * that appears on hover is one nobody reads and one a touch screen cannot ask
 * for.
 *
 * A plate under each, which the fleet map's labels do not have: there they are
 * only ever used on the bare surface, and here they sit over whatever the tile
 * service drew. Dark text alone is legible over a street and invisible over a
 * roof. */
.sab-detail-map .leaflet-tooltip.sab-map-tag {
  background: var(--sab-row);
  border-radius: var(--sab-radius);
  padding: 0 var(--sab-gap-tight);
  box-shadow: 0 0 0 1px var(--sab-rule);
}

/* The reason there is no picture, or half of one, sits directly under the
 * frame it explains rather than a paragraph's gap away from it. */
.sab-detail-map-note {
  margin-top: 0;
}

}
