/* Floating control panels over a full-bleed map. The idiom is lifted from
   roadspeedutils/scripts/signs_map.html so the two pages feel like siblings. */

:root {
  --panel: rgba(20, 23, 28, 0.92);
  /* Opaque twin of --panel. The floating panels sit still and can afford translucency
     plus a backdrop blur; an info bubble sits directly over map labels, and at 0.92 the
     place names read straight through the text. */
  --panel-solid: #14171c;
  --panel-edge: #39404b;
  --text: #e8ecf2;
  --muted: #9aa4b2;
  --accent: #4a90e2;
  --amber: #ffb114;
  --red: #d32b2b;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  font-size: 14px;
  color: var(--text);
  background: #0d0f12;
}

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

.panel {
  position: absolute;
  z-index: 10;
  background: var(--panel);
  border: 1px solid var(--panel-edge);
  border-radius: 8px;
  padding: 10px 12px;
  backdrop-filter: blur(6px);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.45);
}

.controls { top: 12px; left: 12px; width: 260px; }

/* The right-hand column. pointer-events are off on the container so the empty space
   beside a narrow panel does not steal drags from the map. */
.stack {
  position: absolute;
  z-index: 10;
  top: 12px;
  right: 12px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 12px;
  pointer-events: none;
  /* Stop short of the scrubber, so a long selection cannot run off the bottom. */
  max-height: calc(100vh - 100px);
}
.stack > .panel { position: relative; top: auto; right: auto; pointer-events: auto; }

/* The legend keeps its size; the detail panel absorbs whatever is left and scrolls. */
.legend { width: 210px; flex: 0 0 auto; max-height: 40vh; overflow: auto; }
.detail { width: 420px; flex: 0 1 auto; min-height: 0; overflow: auto; }

/* -- collapsing --------------------------------------------------------------- */

.panel-toggle {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  padding: 0;
  background: none;
  border: none;
  border-radius: 6px;
  color: var(--muted);
  cursor: pointer;
}
.panel-toggle:hover { color: var(--text); background: rgba(255, 255, 255, 0.08); }
.panel-toggle svg {
  width: 18px; height: 18px;
  fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round;
}
/* Only ever one glyph on screen: the panel's own icon when shut, a minimise bar when open. */
.panel-toggle .glyph-open { display: none; }

/* Keep the title row clear of the button. */
.panel-body > .row.title { padding-right: 26px; }

.panel.collapsed {
  width: 40px;
  height: 40px;
  min-width: 0;
  padding: 0;
  overflow: hidden;
}
.panel.collapsed .panel-body { display: none; }
.panel.collapsed .panel-toggle { inset: 0; width: 40px; height: 40px; border-radius: 8px; }
.panel.collapsed .panel-toggle .glyph-open { display: block; }
.panel.collapsed .panel-toggle .glyph-close { display: none; }
.panel.collapsed .panel-toggle svg { width: 20px; height: 20px; }

.row { display: flex; gap: 8px; align-items: center; margin: 6px 0; flex-wrap: wrap; }
.row.title { justify-content: space-between; margin-top: 0; }
.small { font-size: 12px; }
.muted { color: var(--muted); }

input[type="search"] { flex: 1; min-width: 0; }
input, select, button {
  font: inherit;
  color: var(--text);
  background: #202630;
  border: 1px solid var(--panel-edge);
  border-radius: 5px;
  padding: 4px 8px;
}
button { cursor: pointer; }
button:hover:not(:disabled) { border-color: var(--accent); }
button:disabled { opacity: 0.45; cursor: default; }
button.link { background: none; border: none; color: var(--muted); padding: 0; }
label { display: flex; align-items: center; gap: 5px; }
/* `display: flex` above beats the user-agent's `[hidden] { display: none }`, so a label
   hidden from script -- the clock picker when only one clock is recorded -- stays on
   screen. Scoped to labels rather than a blanket [hidden] rule so the panels' own
   `hidden` handling is untouched. */
label[hidden] { display: none; }

.filters {
  border: 1px solid var(--panel-edge);
  border-radius: 6px;
  padding: 4px 8px 7px;
  margin: 8px 0 6px;
}
.filters legend { padding: 0 4px; }
.filters label { display: flex; align-items: center; gap: 6px; padding: 2px 0; cursor: pointer; }
.filters label span:nth-of-type(1) { flex: 1; }
.filters .n { font-variant-numeric: tabular-nums; color: var(--muted); font-size: 12px; }

/* -- scrubber ------------------------------------------------------------------ */

.scrubber {
  left: 12px; right: 12px; bottom: 12px;
  padding: 8px 14px 6px;
}
.scrub-row { display: flex; align-items: center; gap: 12px; }
.scrub-row + .scrub-row { margin-top: 2px; justify-content: space-between; }
#play { width: 38px; text-align: center; }
.track { position: relative; flex: 1; height: 30px; }
/* The density strip sits behind the slider so activity is visible before you scrub to it. */
#density { position: absolute; inset: 0; width: 100%; height: 26px; border-radius: 4px; opacity: 0.75; }
#scrub { position: absolute; inset: 0; width: 100%; margin: 0; background: none; border: none; padding: 0; }
.clock { font-variant-numeric: tabular-nums; min-width: 190px; text-align: right; }

/* -- legend -------------------------------------------------------------------- */

.legend-body { display: grid; grid-template-columns: 26px 1fr auto; gap: 4px 8px; align-items: center; }
.legend-body img { width: 22px; height: 22px; object-fit: contain; }
.legend-body .n { font-variant-numeric: tabular-nums; color: var(--muted); }

/* -- detail panel -------------------------------------------------------------- */

.sign { border-top: 1px solid var(--panel-edge); padding: 8px 0; }
.sign:first-child { border-top: none; }
.sign h4 { margin: 0 0 4px; font-size: 13px; }
.sign .meta { color: var(--muted); font-size: 12px; margin-bottom: 5px; }
/* A horizontal ribbon of the sign's states across the selected window. */
.ribbon { display: flex; height: 12px; border-radius: 3px; overflow: hidden; margin-bottom: 5px; }
.ribbon span { display: block; height: 100%; }
/* Every sign renders its own table, so the layout MUST be fixed: with `auto`, each table
   sizes columns to its own content and the time column swung between 132px and 222px,
   leaving the icons at different offsets down the panel. */
.changes { width: 100%; border-collapse: collapse; font-size: 12px; table-layout: fixed; }
.changes td { padding: 2px 4px; border-top: 1px solid rgba(255, 255, 255, 0.06); vertical-align: top; }
.changes td.t { width: 88px; }
.changes td.ico { width: 40px; }
.changes tr { cursor: pointer; }
.changes tr:hover { background: rgba(74, 144, 226, 0.16); }
.changes .t { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* One box for both families. Matrix faces are 36x36 and MS4 panels 44x30, so a square
   box squashed every text panel; contain keeps each one's aspect while they still line up. */
.changes img { width: 30px; height: 22px; object-fit: contain; display: block; }

/* -- misc ---------------------------------------------------------------------- */

.fatal {
  position: absolute; z-index: 50; top: 50%; left: 50%; transform: translate(-50%, -50%);
  background: var(--red); padding: 14px 20px; border-radius: 8px; max-width: 70vw;
}

/* -- marker info bubbles -------------------------------------------------------- */

/* HERE's default bubble is a white box sized shrink-to-fit, which squeezes "M1-M2497A"
   onto two lines. Its chrome is restyled to match the app's panels; the tail is two CSS
   border triangles (::after is the fill, ::before the edge) so both need recolouring or
   a white spike is left pointing at a dark box. */
.H_ib_body {
  background: var(--panel-solid) !important;
  border: 1px solid var(--panel-edge);
  border-radius: 8px;
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.55);
  width: auto !important;
  max-width: none !important;
  overflow: hidden; /* so the header band is clipped by the rounded corners */
}
.H_ib_tail::after { border-top-color: var(--panel-solid) !important; }
.H_ib_tail::before { border-top-color: var(--panel-edge) !important; }
.H_ib_content { margin: 0 !important; padding: 0 !important; }
.H_ib_close svg { fill: var(--muted); }
.H_ib_close:hover svg { fill: var(--text); }

.bubble-content {
  color: var(--text);
  font-size: 13px;
  /* Wide enough that an identifier and its state sit on one line; capped so a long MS4
     legend wraps instead of stretching the bubble off screen. */
  min-width: 260px;
  max-width: 420px;
  padding: 2px 0 4px;
}

.bubble-content table { border-collapse: collapse; width: 100%; }
.bubble-content td { padding: 4px 8px; vertical-align: middle; }
.bubble-content td:first-child { padding-left: 12px; }
.bubble-content td:last-child { padding-right: 12px; }

/* One band per gantry, so a co-located pair reads as two things rather than one long
   list. A full-width row rather than a separate block, so the columns stay shared. */
.bubble-content tr.gantry td {
  background: rgba(74, 144, 226, 0.16);
  padding: 5px 12px;
  font-weight: 600;
  white-space: nowrap;
  border-top: 1px solid var(--panel-edge);
}
.bubble-content tr.gantry:first-child td { border-top: none; }

/* Striping is assigned per row within a gantry: nth-child would count the header rows
   and restart the pattern unpredictably. */
.bubble-content tr.stripe { background: rgba(255, 255, 255, 0.04); }
.bubble-content tr.nodata { color: var(--muted); }
.bubble-content .who { white-space: nowrap; font-variant-numeric: tabular-nums; }
.bubble-content .what { line-height: 1.3; }
.bubble-content .sub { color: var(--muted); font-size: 12px; }
.bubble-content .bad { color: #ff8080; }
.bubble-content td.ico { width: 42px; }
/* Matrix faces are 36x36, MS4 panels 44x30: contain keeps each aspect inside a shared box. */
.bubble-content img { width: 30px; height: 24px; object-fit: contain; display: block; }

/* The drag-rectangle used to select signs. Fixed, not absolute: it is positioned from
   viewport coordinates. */
#selectBox {
  position: fixed; z-index: 20; border: 2px dashed var(--accent);
  background: rgba(74, 144, 226, 0.14); pointer-events: none;
}

/* Armed state, so it is obvious the next drag will draw a box rather than pan. */
button.armed {
  border-color: var(--accent);
  background: rgba(74, 144, 226, 0.28);
  color: var(--text);
}
