/* --- "Θαλασσί γυαλί" palette: frosted teal-tinted panels replacing the old
   plain-white/saturated-blue chrome. Everything decorative (panels, search,
   day-tabs) reads off these variables so .dark-mode below can override the
   whole chrome by redefining a handful of custom properties, not every
   rule. Functional/semantic colors (severity trio, temp bands, Beaufort
   chip color) stay untouched — those encode data, not theme. */
:root {
  --accent: #1f7a80;
  --accent-deep: #145a5f;
  --accent-soft: rgba(31, 122, 128, 0.14);
  --panel-bg: rgba(232, 244, 244, 0.78);
  --panel-border: rgba(31, 122, 128, 0.32);
  --panel-text: #123840;
  --panel-text-muted: #57646b;
}
body.dark-mode {
  --accent: #4fd1c5;
  --accent-deep: #2fa79c;
  --accent-soft: rgba(79, 209, 197, 0.18);
  --panel-bg: rgba(18, 41, 58, 0.82);
  --panel-border: rgba(234, 241, 240, 0.16);
  --panel-text: #eaf1f0;
  --panel-text-muted: #a7b7b6;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; }

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

/* Dark-mode toggle (#dark-mode-toggle in #layer-panel): a CSS filter on
   MapLibre's own render canvas only — ":not(.wave-flow-canvas)" excludes
   the experimental wave-flow particle canvas (see wind_wave.js), which
   already draws its own correct severity colors and would look wrong
   inverted. Markers/panels are separate DOM elements outside the canvas,
   so they're untouched here and instead read the --panel-* variables
   above, which body.dark-mode already redefines. Deliberately not a
   maplibre setStyle() swap — see the comment in app.js for why. */
body.dark-mode #map canvas:not(.wave-flow-canvas) {
  filter: invert(92%) hue-rotate(180deg) brightness(0.94) contrast(0.92);
}
body.dark-mode .maplibregl-ctrl-group {
  background: rgba(18, 41, 58, 0.82);
}
body.dark-mode .maplibregl-ctrl-group button {
  filter: invert(1) hue-rotate(180deg);
}
/* Name-label pills (bay/sea/city/place tiers + beach marker labels) are
   solid white boxes by design in light mode — not part of this palette
   swap. In dark mode a plain white box would stand out harshly against the
   now-dark basemap, so they borrow the same --panel-bg/--panel-text pair
   the frosted panels already use once inside .dark-mode. */
body.dark-mode .marker-label {
  background: var(--panel-bg);
  color: var(--panel-text);
}

#top-bar {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--panel-bg);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  padding: 7px 13px 7px 11px;
  border-radius: 999px;
  border: 0.5px solid var(--panel-border);
  box-shadow: 0 2px 8px rgba(18,41,58,0.14);
  font-size: 12px;
  font-weight: 600;
  color: var(--panel-text);
  pointer-events: none;
}
#top-bar span { white-space: nowrap; }
#top-bar .top-bar-icon { color: var(--accent-deep); flex-shrink: 0; }

.panel {
  position: absolute;
  z-index: 5;
  background: var(--panel-bg);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 0.5px solid var(--panel-border);
  border-radius: 8px;
  padding: 10px 12px;
  box-shadow: 0 2px 8px rgba(18,41,58,0.14);
  font-size: 12px;
  color: var(--panel-text);
}
.panel-title { font-weight: 600; margin-bottom: 6px; color: var(--accent-deep); }
.panel.hidden { display: none; }

.theme-row {
  padding-bottom: 6px;
  margin-bottom: 6px;
  border-bottom: 0.5px solid var(--panel-border);
}

#layer-panel { bottom: 20px; right: 10px; min-width: 140px; }
#legend { bottom: 20px; left: 10px; }
#loading { top: 130px; right: 10px; }
#loading.hidden { display: none; }

#search-panel { top: 12px; right: 10px; width: 220px; padding: 0; background: transparent; box-shadow: none; }
#search-input {
  width: 100%;
  padding: 9px 12px;
  border-radius: 8px;
  border: 0.5px solid var(--panel-border);
  box-shadow: 0 2px 8px rgba(18,41,58,0.14);
  font-size: 13px;
  background: var(--panel-bg);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: var(--panel-text);
}
#search-input:focus { outline: 2px solid var(--accent); }
.search-results {
  margin-top: 4px;
  background: var(--panel-bg);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 0.5px solid var(--panel-border);
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(18,41,58,0.14);
  max-height: 260px;
  overflow-y: auto;
  color: var(--panel-text);
}
.search-results.hidden { display: none; }
.search-result-item {
  padding: 8px 12px;
  font-size: 12px;
  cursor: pointer;
  border-bottom: 0.5px solid var(--panel-border);
}
.search-result-item:last-child { border-bottom: none; }
.search-result-item:hover, .search-result-item.active { background: var(--accent-soft); }
.search-result-place { font-weight: 600; background: rgba(99,153,34,0.14); }
.search-result-place:hover { background: rgba(99,153,34,0.24); }
.search-result-empty { padding: 8px 12px; font-size: 12px; color: var(--panel-text-muted); }

#zoom-hint {
  top: 80px;
  left: 50%;
  transform: translateX(-50%);
  pointer-events: none;
  font-weight: 600;
}
#zoom-hint.hidden { display: none; }

#forecast-panel {
  top: 80px;
  left: 50%;
  transform: translateX(-50%);
  min-width: 320px;
}

/* --- Mobile layout: same panels, repositioned so nothing overlaps on a
   narrow screen. Top row = compact title + search; forecast controls move
   to a full-width bottom bar (the primary interaction while zoomed in);
   layer toggles + legend collapse into small tap-to-expand panels in the
   remaining bottom corners. */
@media (max-width: 640px) {
  #top-bar {
    top: 8px;
    left: 8px;
    padding: 6px 10px;
    font-size: 11px;
  }

  #search-panel { top: 8px; right: 8px; left: auto; width: 48vw; }
  #search-input { padding: 8px 10px; font-size: 12px; }

  #zoom-hint { top: 64px; left: 8px; right: 8px; transform: none; width: auto; text-align: center; font-size: 12px; }

  #loading { top: 64px; right: 8px; font-size: 11px; }

  #forecast-panel {
    top: auto;
    bottom: 8px;
    left: 8px;
    right: 8px;
    transform: none;
    min-width: 0;
    width: auto;
  }

  #layer-panel {
    top: auto;
    bottom: 100px;
    left: 8px;
    min-width: 0;
    max-width: 40vw;
    font-size: 11px;
    padding: 8px 10px;
  }
  #layer-panel .panel-title { font-size: 11px; margin-bottom: 4px; }
  #layer-panel .layer-row { gap: 4px; }

  #legend {
    bottom: 100px;
    left: auto;
    right: 8px;
    max-width: 38vw;
    font-size: 10px;
    padding: 8px 10px;
  }
  #legend .panel-title { font-size: 11px; margin-bottom: 4px; }
  #legend .legend-row { gap: 5px; margin: 2px 0; }

  /* The 100px bottom offset above only exists to leave room for
     #forecast-panel's full-width bar once a beach is picked. Whenever it's
     still hidden (bay/sea zoom levels, no beach selected yet) that gap is
     just wasted space pushing these two low over the map — drop them down
     to the same bottom edge as the forecast bar would use. */
  body:has(#forecast-panel.hidden) #layer-panel,
  body:has(#forecast-panel.hidden) #legend {
    bottom: 10px;
  }

  /* Beaufort chips (bays + sea regions) are sized for desktop map real
     estate; shrink both variants down on phones so they don't dominate a
     small screen at the zoom levels they appear at. */
  .beaufort-chip { font-size: 10px; gap: 4px; }
  .beaufort-chip::before { width: 6px; height: 6px; }
  .sea-region-chip { font-size: 12px; }
  .sea-region-chip::before { width: 7px; height: 7px; }
}

.layer-row { display: flex; align-items: center; gap: 6px; cursor: pointer; }

.day-tabs { display: flex; gap: 4px; margin-bottom: 8px; }
.day-tab {
  flex: 1;
  text-align: center;
  padding: 5px 4px;
  border-radius: 6px;
  border: 0.5px solid var(--panel-border);
  background: rgba(255,255,255,0.4);
  color: var(--panel-text);
  cursor: pointer;
  font-size: 11px;
  line-height: 1.3;
  user-select: none;
}
.day-tab .weekday { display: block; font-weight: 600; }
.day-tab .daynum { display: block; color: var(--panel-text-muted); font-size: 10px; }
.day-tab.active { background: var(--accent-deep); border-color: var(--accent-deep); color: #fff; }
.day-tab.active .daynum { color: rgba(255,255,255,0.75); }

/* Forecast model hasn't published this far out yet (see dataAvailableForDay
   in wind_wave.js) — dashed border + dimmed text instead of looking identical
   to a normal, just-currently-selected-elsewhere tab. Still clickable: the
   point is to set expectations, not to hide the tab. */
.day-tab.day-tab-nodata { border-style: dashed; opacity: 0.55; }
.day-tab.day-tab-nodata.active { background: #90a4ae; border-color: #90a4ae; opacity: 1; }

.hour-row { display: flex; align-items: center; gap: 8px; }
.hour-row input[type="range"] { flex: 1; }
.hour-label { font-weight: 600; font-variant-numeric: tabular-nums; min-width: 42px; text-align: right; }

.legend-row { display: flex; align-items: center; gap: 8px; margin: 3px 0; }
.dot { width: 12px; height: 12px; border-radius: 50%; display: inline-block; border: 1px solid rgba(0,0,0,0.3); }
.line { width: 22px; height: 0; border-top: 3px solid; display: inline-block; }
.wind-sample { border-color: #616161; }
.wave-sample { border-color: #1565c0; }

/* --- beach marker: dual-ring (outer ring + inner dot, both in the
   severity color) with small direction icons pivoting around it --- */
.beach-marker { position: relative; width: 0; height: 0; cursor: pointer; }

.marker-ring {
  position: absolute;
  left: 50%; top: 50%;
  width: 22px; height: 22px;
  border-radius: 50%;
  border: 2.5px solid currentColor;
  background: rgba(255,255,255,0.55);
  transform: translate(-50%, -50%);
}
/* Sea/air temperature on beach markers: the actual value, not just a color
   cue (an earlier ring-only design turned out too subtle to read as
   "temperature" rather than "a second, unrelated marker nearby", especially
   next to the many near-duplicate beach points in the source OSM data). Sit
   side by side directly below the ring at the same clearance the name label
   uses above (44px) — clears the wind/wave icons' full 360° sweep (~41px max
   reach) the same way, tested at multiple rotations.
   No background box — the icon (SEA_TEMP_ICON_SVG/AIR_TEMP_ICON_SVG, colored
   via `color` in JS) carries the temp-band signal instead. The value itself
   is dark text with a white halo (multi-direction text-shadow, the standard
   map-label trick) rather than a JS-computed black/white pick: the basemap
   underneath is a live, panned/zoomed tile image, so a halo stays legible
   against whatever color it lands on, where any single fixed text color
   would only be right for some of them. */
.temp-pill {
  position: absolute;
  left: 50%; top: 44px;
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 2px;
  pointer-events: none;
}
.temp-icon { display: flex; filter: drop-shadow(0 0 1.5px #fff) drop-shadow(0 0 1.5px #fff); }
.temp-value {
  font-size: 10px;
  font-weight: 700;
  color: #1a1d1c;
  text-shadow: 0 0 2px #fff, 0 0 2px #fff, 0 0 2px #fff, 0 0 2px #fff;
}
.temp-pill-sea { transform: translate(calc(-100% - 2px), 0); }
.temp-pill-air { transform: translate(2px, 0); }
/* Layer toggles (js/layers/wind_wave.js) — a class on the map container
   instead of tracking every pill/dot element in JS. */
#map.hide-sea-temp .temp-pill-sea { display: none; }
#map.hide-air-temp .temp-pill-air { display: none; }
/* Zoom gating (MIN_ZOOM_BEACH_TEMPS in wind_wave.js): two pills per beach at
   island-wide zoom pile into an unreadable slab, and sea temp barely varies
   between neighbouring beaches anyway — hide them until you're zoomed in on
   a handful of beaches. The per-bay air-temp dots stay on as the sampled view. */
#map.zoomed-out-temps .beach-marker .temp-pill { display: none; }

/* Coarser tiers (sea region at country zoom, bay in between) show a mean of
   the surrounding beaches instead — same pills, anchored to each marker's own
   geometry. Sea-region pills go above the chip to clear its wave icon's 46px
   downward sweep; bays have no icons, so theirs sit just under the chip. */
.sea-region-marker .temp-pill { top: auto; bottom: 50px; }
.beaufort-badge .temp-pill { top: 16px; }

/* Sun/cloud/rain/snow glyph (js/layers/wind_wave.js's WEATHER_ICON_SVG,
   weather_code from Open-Meteo — see build_forecast_cache.py). A single
   fixed-position badge, not a value+icon pill like temperature, since it's
   4 categories to pick between rather than a number to format. No per-beach
   version — weather doesn't vary beach-to-beach the way wind direction
   does, so it lives on the sea-region and place/city tiers only (see
   .place-marker/.city-marker below). Sea-region tier: centered above
   the temp pills, same reasoning as those pills accepting the wave arrow's
   360° sweep as a known trade-off rather than dynamically dodging it. */
.weather-icon {
  position: absolute;
  left: 50%; top: 50%;
  pointer-events: none;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,0.35));
}
.sea-region-marker .weather-icon { left: 50%; top: auto; bottom: 68px; transform: translate(-50%, 0); }
#map.hide-weather .weather-icon { display: none; }
/* Hand over cleanly: once per-beach pills appear, the bay means would just
   duplicate them over the same coastline. */
#map:not(.zoomed-out-temps) .beaufort-badge .temp-pill { display: none; }

/* Swim/surf read: sits on its own zero-size anchor (.swim-surf-anchor,
   positioned via JS in positionSwimSurf() toward the real sea, not a fixed
   spot on the marker — a fixed offset landed on dry land as often as on
   water depending on which way a given beach's coastline actually faces).
   Swim badge is colored per-beach in JS (reuses the severity trio, see
   swimSuitability() — this IS a danger/comfort signal, unlike temperature);
   surf badge has one fixed color and is only ever shown at all (see
   isGoodForSurf()). */
/* Thin leader line from the marker to the badges — every marker gets one,
   not just the "weird" cases, since the badge pair sits at a fixed
   distance in some direction regardless of beach; a dashed, low-opacity
   line reads as "these two belong together" the same way a map-label
   leader line does, without fighting the water-placement constraint. */
.swim-surf-leader { position: absolute; left: 50%; top: 50%; overflow: visible; pointer-events: none; }
.swim-surf-leader line { stroke: rgba(40,48,44,.4); stroke-width: 1.5; stroke-dasharray: 3 3; }
.swim-surf-anchor { position: absolute; left: 50%; top: 50%; width: 0; height: 0; }
.swim-badge, .surf-badge {
  position: absolute;
  top: 0;
  width: 20px; height: 20px;
  border-radius: 50%;
  font-size: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 2px rgba(0,0,0,.35);
  pointer-events: none;
}
.swim-badge { left: 50%; transform: translate(calc(-100% - 3px), -50%); }
.surf-badge { left: 50%; transform: translate(3px, -50%); background: #00897b; }
#map.zoomed-out-temps .beach-marker .swim-badge,
#map.zoomed-out-temps .beach-marker .surf-badge,
#map.zoomed-out-temps .beach-marker .swim-surf-leader { display: none; }
.marker-dot {
  position: absolute;
  left: 50%; top: 50%;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 0 2px #fff;
  transform: translate(-50%, -50%);
}

.arrow-pivot { position: absolute; left: 50%; top: 50%; width: 0; height: 0; }

/* Marker elements don't rotate with the map (MapLibre default), but the
   inline rotate() on .arrow-pivot above is a real compass bearing computed
   assuming screen-up = north. Rotating the map changes what "up" means on
   screen, so without this counter-rotation the arrows silently point the
   wrong way whenever the user rotates the map. --map-bearing is set to
   -map.getBearing() on #map (see js/layers/wind_wave.js) and inherits down
   to every marker automatically — no per-marker JS needed on rotate. */
.bearing-comp { position: absolute; left: 0; top: 0; width: 0; height: 0; transform: rotate(var(--map-bearing, 0deg)); }

.dir-icon {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  overflow: visible;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,0.35));
}
/* Distance from the marker center — wind sits closer in, wave further out,
   so the two arrows form separate rings instead of overlapping each other
   or the ring/chip they're pivoting around. */
.wind-pivot .dir-icon { bottom: 14px; }
.wave-pivot .dir-icon { bottom: 20px; }
.sea-region-marker .wave-pivot .dir-icon { bottom: 26px; }

.marker-label {
  /* Wind/wave icons pivot a full 360° around the marker (real compass
     bearings), reaching ~41px from center at worst (wave icon, pointing
     straight up toward the label). 38px leaves a small but clean gap —
     tested at multiple rotations; anything much tighter starts clipping
     the wave icon's tip. */
  position: absolute;
  bottom: 38px; left: 50%;
  transform: translate(-50%, 0);
  white-space: nowrap;
  font-size: 10px;
  background: rgba(255,255,255,0.85);
  padding: 1px 4px;
  border-radius: 4px;
  pointer-events: none;
}
/* Zoom gating (MIN_ZOOM_BEACH_LABELS in wind_wave.js — its own, shallower
   threshold than the temp pills' MIN_ZOOM_BEACH_TEMPS). A long coastline at
   wide zoom has dozens of these on screen at once, which piled into a solid
   wall of overlapping white boxes (real user screenshot). Hidden until
   there's real room for them; the name is still reachable at any zoom via a
   native hover title on the ring (see createBeachEntry). */
#map.hide-beach-labels .beach-marker .marker-label { display: none; }

/* --- Beaufort chip, one per named bay: a bare colored label (no box, no
   border) so dozens of these across a busy coastline read as light text
   annotations rather than stacked stickers. Color still comes from JS
   (setChipValue sets `color`, `.chip-label`'s text inherits it) — only the
   box/border/fill was removed here. Legibility over whatever the map tile
   underneath happens to be comes from the white halo (text-shadow) and the
   small solid dot, the same trick already used for temp-pill values. --- */
.beaufort-badge { position: relative; width: 0; height: 0; }
.beaufort-chip {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  font-weight: 800;
  white-space: nowrap;
  cursor: default;
  /* Bays/sea regions now render at the same zoom band as the (much more
     numerous) beach markers — real testing found the chip was technically
     always on top (z-order was never the problem) but easy to miss by eye
     next to dozens of small beach dots/labels. Bumped weight/size + a
     stronger halo than the temp-pill trick uses elsewhere, still zero
     background/border, so it reads through clutter on contrast alone
     rather than by competing as another box. */
  text-shadow:
    0 0 2px rgba(255,255,255,0.95), 0 0 2px rgba(255,255,255,0.95),
    0 0 4px rgba(255,255,255,0.85), 0 0 4px rgba(255,255,255,0.85);
}
.beaufort-chip::before {
  content: "";
  width: 8px; height: 8px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 0 2.5px rgba(255,255,255,0.85);
  flex-shrink: 0;
}

/* Wind-grid detail points around a bay's centroid, revealed on deep zoom
   (MIN_ZOOM_BAY_DETAIL) — deliberately lighter than .beaufort-chip (no dot,
   softer halo) so they read as "finer detail" rather than competing with
   the bay's own chip, now that both are borderless labels rather than one
   being a smaller box than the other. No manual centering transform
   needed: unlike the ring/chip markers above, this is a single plain
   element passed straight to maplibregl's Marker, which centers it on
   anchor:'center' by itself. */
.bay-detail-chip {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  white-space: nowrap;
  cursor: default;
  text-shadow: 0 0 2px rgba(255,255,255,0.85), 0 0 2px rgba(255,255,255,0.85);
}

/* --- sea-region overview: sparse Beaufort chip + wave direction icon per
   named sea/gulf --- */
.sea-region-marker { position: relative; width: 0; height: 0; }

.sea-region-chip { font-size: 15px; gap: 6px; }
.sea-region-chip::before { width: 8px; height: 8px; }

/* Name labels for the coarser tiers (sea region / city / place) used to be
   permanent text under the icon — real feedback flagged them as noise even
   after they'd already lost their box, then asked for hover-only instead of
   fainter-but-still-always-on. Now a native `title` on the weather-icon
   element itself (set in wind_wave.js's create*Entry functions) — no
   markup/CSS needed, same pattern .bay-detail-chip already uses for its
   wind-speed detail. */
.city-marker { position: relative; width: 0; height: 0; }
.city-marker .weather-icon { left: 50%; top: 50%; transform: translate(-50%, -50%); }
#map.hide-city-weather .city-marker { display: none; }

/* Weather-only place (island/area) marker — visually identical to the city
   marker above, but deliberately its own class rather than reusing
   .city-marker: it's on the "Καιρικές Συνθήκες" toggle (hide-weather, same
   as the sea-region icon) not the separate "Καιρός σε Πόλεις" one, since a
   user might want one on and the other off (js/layers/wind_wave.js's
   createPlaceEntry). */
.place-marker { position: relative; width: 0; height: 0; }
.place-marker .weather-icon { left: 50%; top: 50%; transform: translate(-50%, -50%); }
#map.hide-weather .place-marker { display: none; }

.beach-popup h3 { margin: 0 0 6px; font-size: 14px; }
.beach-popup p { margin: 3px 0; font-size: 12px; }
.sev-badge {
  display: inline-block;
  color: #fff;
  padding: 2px 8px;
  border-radius: 10px;
  font-weight: 600;
  font-size: 11px;
}
