:root {
  --bg: #0f1b2a;
  --panel: #ffffff;
  --ink: #1b2733;
  --muted: #5a6b7b;
  --accent: #1f5fa8;
  --header-h: 48px;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--ink);
}

/* Header + map stack vertically; the map region flexes to fill what the fixed
   header above it leaves, so no manual height subtraction is needed. */
body {
  display: flex;
  flex-direction: column;
}

#app-header {
  flex: 0 0 auto;
  height: var(--header-h);
  padding: 0 18px;
  background: var(--bg);
  color: #fff;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 12px;
}

#app-header h1 {
  margin: 0;
  font-size: 1.2rem;
  font-weight: 600;
}

/* Unofficial / work-in-progress caution, now a compact amber tag beside the
   title (in the old banner's amber) rather than a full-width strip. */
.wip-tag {
  flex: 0 0 auto;
  font-size: 0.72rem;
  font-weight: 600;
  color: #f6c445;
  background: rgba(246, 196, 69, 0.14);
  border: 1px solid rgba(246, 196, 69, 0.4);
  border-radius: 999px;
  padding: 2px 9px;
  white-space: nowrap;
  cursor: default;
}

/* Imprint link, right-aligned in the title bar. Same size as the caution tag
   but plain white-on-black — no pill, no highlight (margin-left:auto pushes it
   to the far right of the flex header). */
.imprint-link {
  margin-left: auto;
  flex: 0 0 auto;
  font-size: 0.72rem;
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
}

.imprint-link:hover,
.imprint-link:focus {
  text-decoration: underline;
}

#layout {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
}

#map {
  flex: 1 1 auto;
  height: 100%;
  /* No basemap tiles (dropped to save at-sea VSAT transfer — see main()); this
     sea-tone fills the map where the current field doesn't cover. */
  background: #dfe7ee;
}

#sidebar {
  flex: 0 0 260px;
  height: 100%;
  overflow-y: auto;
  background: var(--panel);
  border-left: 1px solid #d8e0e8;
  padding: 14px 16px;
}

/* Sidebar sections are collapsible <details>; the <summary> carries the old <h2>
   look plus a disclosure caret. Freshness, ships and currents open by default;
   the read-once/occasional panels (vorticity, drift, awaiting) start collapsed to
   keep the initial column short. */
#sidebar summary {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 2px 0;
}
#sidebar summary::-webkit-details-marker {
  display: none;
}
#sidebar summary::before {
  content: "";
  flex: 0 0 auto;
  width: 0;
  height: 0;
  border-left: 5px solid var(--muted);
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
}
#sidebar .panel[open] > summary::before {
  transform: rotate(90deg);
}
#sidebar .panel[open] > summary {
  margin-bottom: 8px;
}
#sidebar summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: no-preference) {
  #sidebar summary::before {
    transition: transform 0.12s ease;
  }
}

#sidebar .count {
  color: var(--accent);
  font-weight: 600;
}

#sidebar .hint {
  margin: 0 0 10px;
  font-size: 0.75rem;
  color: var(--muted);
}

#sidebar .panel {
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid #e3e9ef;
}
#sidebar .panel:last-child {
  margin-bottom: 0;
  padding-bottom: 0;
  border-bottom: none;
}

.status-row {
  margin-top: 6px;
}

.status-label {
  display: block;
  font-size: 0.72rem;
  color: var(--muted);
}

.status-value {
  display: block;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

.ship-row {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 0.78rem;
  line-height: 1.6;
  font-variant-numeric: tabular-nums;
}

.legend-bar {
  height: 12px;
  border-radius: 3px;
  border: 1px solid #d8e0e8;
}

.legend-scale {
  display: flex;
  justify-content: space-between;
  margin-top: 3px;
  font-size: 0.72rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

#awaiting-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

#awaiting-list li {
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  background: #eef3f8;
  color: var(--ink);
  border: 1px solid #d8e0e8;
  border-radius: 4px;
  padding: 2px 6px;
}

#awaiting-list li.empty {
  background: none;
  border: none;
  color: var(--muted);
  font-style: italic;
}

/* Speed-shading raster: show the native CMEMS grid cells as sharp pixels rather
   than letting the browser bilinear-smooth the upscaled bitmap. */
.crisp-raster {
  image-rendering: -moz-crisp-edges; /* Firefox */
  image-rendering: pixelated; /* Chrome/Safari/Edge */
}

/* Time slider (bottom-centre): scrubs the speed / ζ/f shadings through the CMEMS
   forecast at 12 h steps. A plain positioned element inside the map container (not
   an L.control) so it can centre and cap its width; shares the .map-control look.
   z-index sits above the map panes/popups (≤700) but below Leaflet's controls
   (1000), so an expanded control dock overlapping it on a short window draws on
   top rather than being hidden behind the slider. */
.time-slider-control {
  position: absolute;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 800;
  width: min(92vw, 560px);
  background: var(--panel);
  color: var(--ink);
  border-radius: 4px;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
  padding: 8px 12px 6px;
  font-size: 0.8rem;
}

.time-slider-control .ts-range {
  width: 100%;
  margin: 0;
  accent-color: var(--accent); /* tint the track/handle in supporting browsers */
  cursor: pointer;
}

.time-slider-control .ts-ticks {
  display: flex;
  justify-content: space-between;
  margin-top: 2px;
  font-size: 0.66rem;
  color: var(--muted);
}

/* The selected frame's valid time, tucked into the box's lower-right corner. */
.time-slider-control .ts-time {
  margin-top: 3px;
  text-align: right;
  font-size: 0.7rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.time-slider-control .ts-tick.ts-now {
  color: var(--accent);
  font-weight: 600;
}

/* On a narrow phone the slider would crowd the sidebar-less single column; keep it
   readable by shrinking the tick text and letting it hug the map width. */
@media (max-width: 640px) {
  .time-slider-control {
    width: 94vw;
    bottom: 10px;
  }
  .time-slider-control .ts-ticks {
    font-size: 0.6rem;
  }
}

/* Cursor coordinate readout (lower-left): plain text on a translucent white
   chip showing the pointer's lon/lat in decimal degrees. A positioned element
   inside the map container (like the time slider), not an L.control, so it hugs
   the corner without joining the attribution flow. Sits low in the z-stack
   (above panes, below the control dock/slider) and ignores pointer events so it
   never blocks a click or hover on the map beneath it. Hidden until the pointer
   is over the map (toggled from JS). */
.cursor-readout {
  position: absolute;
  left: 8px;
  bottom: 8px;
  z-index: 700;
  background: rgba(255, 255, 255, 0.5);
  color: var(--ink);
  border-radius: 3px;
  padding: 2px 7px;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  pointer-events: none;
}
.cursor-readout.hidden {
  display: none;
}

/* Shared box style for the top-right chrome — the control dock and the time
   slider — so they read as one set: white card, soft shadow, small type. */
.map-control {
  background: var(--panel);
  color: var(--ink);
  border: none;
  border-radius: 4px;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
  padding: 8px 10px;
  font-size: 0.8rem;
}

/* The control dock: one top-right box with a header bar, a tab strip, and one
   visible body at a time (Instruments / Currents / Ships / Deploy), so the
   footprint is the tallest single tab, not the sum of stacked boxes. Overrides the
   shared .map-control padding so the bar and tabs meet the box edges; each body
   carries its own padding. */
.control-dock {
  width: 268px;
  padding: 0;
}
/* Collapsed, the box shrinks to just "Controls  v" instead of keeping the full
   open width as an empty bar. */
.control-dock.collapsed {
  width: auto;
}
/* Top bar: the tab strip + collapse caret when open; a "Controls" label + caret
   when collapsed (the bar is then all that remains). */
.dock-bar {
  display: flex;
  align-items: stretch;
  border-bottom: 1px solid #d8e0e8;
}
.control-dock.collapsed .dock-bar {
  border-bottom: none;
}
/* The "Controls" label is only for the collapsed state; hidden while open. */
.dock-title {
  display: none;
  align-items: center;
  flex: 1 1 auto;
  padding: 6px 0 6px 10px;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}
.control-dock.collapsed .dock-title {
  display: flex;
}
.dock-collapse {
  flex: 0 0 auto;
  align-self: center;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  cursor: pointer;
  color: var(--muted);
  margin: 0 4px;
  padding: 3px;
  border-radius: 4px;
}
.dock-collapse:hover {
  color: var(--ink);
  background: #eef3f8;
}
.dock-collapse svg {
  display: block;
}
/* Chevron points up when the dock is open (click to collapse), down when it's
   collapsed (click to expand). */
.control-dock:not(.collapsed) .dock-collapse svg {
  transform: rotate(180deg);
}
@media (prefers-reduced-motion: no-preference) {
  .dock-collapse svg {
    transition: transform 0.15s ease;
  }
}
.dock-tabs {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
}
.control-dock.collapsed .dock-tabs {
  display: none;
}
.dock-tab {
  flex: 1 1 auto;
  min-width: 0;
  padding: 7px 2px;
  border: none;
  border-bottom: 2px solid transparent;
  background: none;
  font: inherit;
  font-size: 0.73rem;
  font-weight: 600;
  white-space: nowrap;
  color: var(--muted);
  cursor: pointer;
}
.dock-tab:hover {
  color: var(--ink);
}
.dock-tab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
/* Cap a tall tab at the space the dock actually has and let it scroll, rather than
   grow past the viewport as the old stacked boxes did. The dock sits inside the map
   (a 100vh − header region) ~10px below its top, under its tab bar, so the body's room
   is the viewport minus the header and that chrome: calc(100vh − header − 60px) keeps
   it clear of the map's bottom edge on a short window. The 80px reserves the top margin,
   the tab bar, and the map's bottom-right Leaflet attribution link so the panel never
   sits over it. The 720px cap clears the tallest tab (the Deploy tool's three
   compartments, ~600px) so it doesn't scroll on a roomy screen either. */
.dock-body {
  padding: 8px 10px;
  max-height: min(calc(100vh - var(--header-h) - 80px), 720px);
  overflow-y: auto;
}
/* Small group caption inside a tab (e.g. "Surface shading" above the radios). */
.dock-cap {
  display: block;
  margin: 2px 0 4px;
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
/* Placeholder shown in the Ships tab before any vessel reports a fix. */
.dock-empty {
  margin: 0;
  font-size: 0.75rem;
  font-style: italic;
  color: var(--muted);
}

/* A sidebar legend hidden while its shading is off (contextual legends): the
   speed legend shows only under the "Current speed" shading, ζ/f only under
   "Vorticity ζ/f". Toggled from onShadingChange in app.js. */
.legend-hidden {
  display: none;
}

.batch-row {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  line-height: 1.6;
}

.batch-row input {
  cursor: pointer;
  margin: 0;
}

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

/* Line swatch for the overlay (True track / Forecast / Hindcast) rows — a
   short bar keying the checkbox to the coloured layers it toggles, as the
   round .batch-swatch keys a batch row to its circular markers. */
.batch-line-swatch {
  width: 14px;
  height: 3px;
  border-radius: 1px;
  flex: 0 0 auto;
}

/* Divider between the overlay (line) rows and the per-batch (marker) rows. */
.batch-divider {
  border: none;
  border-top: 1px solid #d8e0e8;
  margin: 6px 0;
}

/* PoC deploy tool (interactive multi-click deployment planner). Renders into the
   dock's Deploy tab (the dock is the box), so it no longer sets its own width; it
   keeps the .ft-* look — toggle/clear buttons, a hint, a status line — plus its
   own .pt-* knob rows. The crosshair cursor is worn by the map while armed. */
.deploy-tool .ft-btn {
  display: block;
  width: 100%;
  margin: 0 0 5px;
  padding: 4px 6px;
  border: 1px solid #c3ccd6;
  border-radius: 3px;
  background: #f4f6f8;
  color: var(--ink);
  font: inherit;
  font-size: 0.75rem;
  cursor: pointer;
}
.deploy-tool .ft-btn:hover {
  background: #e8edf2;
}
.deploy-tool .ft-toggle.on {
  background: #16a34a;
  border-color: #0f7a37;
  color: #fff;
}
.deploy-tool .ft-hint {
  margin: 2px 0 0;
  font-size: 0.7rem;
  color: var(--muted);
}
.deploy-tool .ft-status {
  margin: 4px 0 0;
  min-height: 1em;
  font-size: 0.7rem;
  color: #0f7a37;
}
/* Deploy tool compartments: the tab body is a top color bar + three captioned
   sections (Settings · Click to place · Waypoints) + a manage/status footer. Each
   section is set off by a top rule and a small uppercase caption, so the three
   placement concerns read apart. */
.deploy-tool .pt-section {
  margin: 9px 0 0;
  padding: 9px 0 0;
  border-top: 1px solid #d7dde4;
}
/* Rule setting the manage footer (Download / Clear) off from the CSV compartment. */
.deploy-tool hr.pt-hr {
  margin: 9px 0 7px;
  border: 0;
  border-top: 1px solid #d7dde4;
}
.deploy-tool .pt-section-cap {
  display: block;
  margin-bottom: 6px;
  font-size: 0.66rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}
/* Deploy tool's compact knob inputs — a label + a narrow number field or a
   checkbox per row (drop spacing, ship speed, forecast horizon, drift on/off). */
.deploy-tool .pt-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 4px;
  font-size: 0.72rem;
  cursor: pointer;
}
.deploy-tool .pt-label {
  flex: 1 1 auto;
}
.deploy-tool .pt-num {
  flex: 0 0 69px;
  width: 69px;
  padding: 2px 4px;
  border: 1px solid #c3ccd6;
  border-radius: 3px;
  background: #fff;
  color: var(--ink);
  font: inherit;
  font-size: 0.72rem;
}
.deploy-tool .pt-check {
  margin: 0;
  cursor: pointer;
}
/* Import (paste-mask) textarea: full-width, monospace so lon,lat columns line up,
   sitting above the "Load file…" / "Place from CSV" buttons. */
.deploy-tool .pt-import {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin: 6px 0 5px;
  padding: 4px 6px;
  border: 1px solid #c3ccd6;
  border-radius: 3px;
  background: #fff;
  color: var(--ink);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.7rem;
  resize: vertical;
}
/* Synced-snapshot dot legend: a caption, the tab20c band bar (one hard-edged swatch
   per mark), and its three ticks (run · mid · horizon, the ticks tracking the run's
   horizon), so a dot's colour maps to its time since the run began (the array's shape
   at that t0). */
.deploy-tool .pt-legend {
  margin: 6px 0 0;
}
.deploy-tool .pt-legend-cap {
  display: block;
  font-size: 0.68rem;
  color: var(--muted);
  margin-bottom: 3px;
}
.deploy-tool .pt-legend-bar {
  height: 8px;
  border-radius: 2px;
  border: 1px solid rgba(0, 0, 0, 0.15);
}
.deploy-tool .pt-legend-ticks {
  display: flex;
  justify-content: space-between;
  margin-top: 1px;
  font-size: 0.62rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
/* The placement preview's floating label (drop count · path length · transit
   time), pinned at the cursor while the path is drawn. Reuses the deploy green so
   it reads as part of the ephemeral preview, not a map tooltip; the arrow is
   dropped since it labels a point, not a callout. */
.leaflet-tooltip.pt-preview-label {
  background: rgba(255, 255, 255, 0.92);
  border: 1px solid #16a34a;
  border-radius: 3px;
  padding: 1px 5px;
  color: #0f7a37;
  font-size: 0.7rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  box-shadow: none;
  white-space: nowrap;
  pointer-events: none;
}
.leaflet-tooltip.pt-preview-label::before {
  display: none;
}
.leaflet-container.deploy-cursor {
  cursor: crosshair;
}

/* Ship markers (Marion Dufresne, Agulhas II): a coloured disc with a white ring
   and a boat glyph, set apart from the small blue drifter circles. The inner
   .ship-disc carries the per-vessel fill (set inline); the crimson vs near-black
   tells the two vessels apart. Overrides the default .leaflet-div-icon box. */
.ship-marker {
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
}

.ship-disc {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  box-sizing: border-box;
  background: #1a1a1a;
  border: 2px solid #fff;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}

/* Glider marker: a coloured diamond (rotated square) so the XSPAR buoy and the
   seagliders read apart from the drifters' circles. The inner <span> carries the
   per-type fill (set inline); the white cased border matches the ship marker. */
.glider-marker span {
  display: block;
  width: 12px;
  height: 12px;
  margin: 2px;
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
  transform: rotate(45deg);
}

/* Selected (click-to-highlight): scale the diamond up in place. Keeps rotate in
   the transform so the scale composes with it; the icon size/anchor are
   unchanged, so the marker doesn't jump. */
.glider-marker-selected span {
  transform: rotate(45deg) scale(1.45);
}

.popup strong {
  font-size: 0.95rem;
}

.popup-label {
  color: var(--muted);
}

.map-error {
  display: flex;
  height: 100%;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-size: 0.9rem;
}

/* Narrow window: the side-by-side sidebar no longer fits, so the layout stacks
   and the sidebar drops below the map. A tall (high-aspect-ratio) window has the
   vertical room to spare for it there. */
@media (max-width: 720px) {
  #layout {
    flex-direction: column;
  }
  #map {
    height: auto;
    min-height: 0;
  }
  #sidebar {
    flex: 0 0 auto;
    max-height: 35vh;
    border-left: none;
    border-top: 1px solid #d8e0e8;
  }
}

/* Narrow AND short — both dimensions forbid it — so even a bottom strip isn't
   worth the room: the sidebar drops out and the map takes the whole viewport. Its
   freshness/ship/awaiting detail is reference data, and the layer + ship controls
   stay reachable in the map's control dock. The height cutoff is set so the
   sidebar gives way to the map once its 35vh strip would eat into a short window,
   rather than clinging on until it owns half the screen. */
@media (max-width: 720px) and (max-height: 760px) {
  #sidebar {
    display: none;
  }
}
