/* ============================================================================
   MAP DISPLAY STYLES
   Map cards, markers, pills, labels, clusters, shadows
   ============================================================================ */

/* ============================================================================
   MAPBOX CRITICAL CSS
   Required for map to render correctly
   Note: !important flags are allowed for Mapbox overrides only
   ============================================================================ */

.mapboxgl-map {
  position: relative;
  width: 100%;
  height: 100%;
  z-index: var(--layer-base);
}

.mapboxgl-canvas {
  position: absolute;
  left: 0;
  top: 0;
  /* Google Maps cursor scheme: plain arrow at rest — its hotspot IS its
     visible tip, so aiming at small markers is pixel-exact (the grab hand's
     hotspot sits mid-palm, ~10px off the perceived fingertip). */
  cursor: default;
}

.mapboxgl-canvas-container {
  position: absolute;
  inset: 0;
  z-index: var(--layer-base);
}

.mapboxgl-ctrl {
  box-sizing: border-box;
}

/* Mapbox logo dimmed to sit quietly in the corner (operator 2026-08-29).
   60% keeps it clearly visible/legible per Mapbox attribution terms;
   opacity works identically on both themes. Third-party injected element. */
.mapboxgl-ctrl-logo {
  opacity: 0.6;
}

.mapboxgl-marker {
  cursor: pointer;
}

.mapboxgl-popup {
  border-radius: 8px;
}

.mapboxgl-popup-content {
  border-radius: 8px;
  background: var(--popup-bg);
  color: var(--popup-text);
  overflow: hidden;
}

.mapboxgl-popup-close-button {
  color: var(--popup-text);
}

.mapboxgl-popup-track-pointer {
  -webkit-user-select: none;
  user-select: none;
}

.mapboxgl-ctrl-geocoder--input {
  font-size: 14px;
  font-weight: 400;
}

.mapboxgl-ctrl-geocoder--input::placeholder {
  font-size: 14px;
  font-weight: 400;
}

/* Mapbox button styling is in components.css (single source of truth) */

/* ============================================================================
   MAP CONTAINER & AREA
   ============================================================================ */

.map-container {
  position: absolute;
  inset: 0;
  opacity: 0; /* Start hidden to prevent flash - JS sets to 1 */
  z-index: var(--layer-base);
}

.map-area {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: var(--layer-base);
}

@media (max-width: 530px) {
  .map-area {
    /* The map begins UNDER the opaque mobile header (operator 2026-07-05):
       the visible map is exactly the bounds that filter the results — no
       hidden strip can count entries the user cannot see. */
    top: calc(var(--header-h) + var(--safe-top));
    left: 0;
    right: 0;
    /* CAPPED at the bottom (operator 2026-07-06): height pinned to the SMALL
       viewport (Safari bar visible), so the bar's height changes can never
       resize the map — no re-layout jolt, bounds never move. Scrolling
       content is NOT capped; only the map obeys the resting geometry (same
       law as the top edge: wobble shows as a band, never as movement). */
    bottom: auto;
    height: calc(100svh - var(--header-h) - var(--safe-top));
  }
}

/* ============================================================================
   MAP LOADING OVERLAY
   Server-rendered inside .map-area; removed by map.js on 'map:ready'.
   Sits above the map container but below any panels — panels can open over it
   without issue. Fades out cleanly before being removed from the DOM.
   ============================================================================ */

.map-loading {
  position: fixed;
  top: 45vh;
  left: 50vw;
  transform: translate(-50%, -50%);
  z-index: var(--layer-content);
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.map-loading--hidden {
  opacity: 0;
}

.map-loading-text {
  font-size: 16px;
  color: #fff;
  font-weight: 500;
}

.map-loading-dots {
  display: inline-block;
  width: 1.2em;
  text-align: left;
}

.map-loading-dots span {
  display: inline-block;
  opacity: 0.2;
  animation: map-loading-dot 1.4s infinite ease-in-out;
}

.map-loading-dots span:nth-child(2) { animation-delay: 0.2s; }
.map-loading-dots span:nth-child(3) { animation-delay: 0.4s; }

@keyframes map-loading-dot {
  0%, 80%, 100% { opacity: 0.2; }
  40%           { opacity: 1; }
}

/* GLOBE SWITCHER VEIL (operator 2026-08-18): the projection swap repaints the
   whole canvas from the base tile color ("grey tiles"), so the swap hides
   under this tint — fade in 0.3s (same ease as .map-loading above), the swap
   and its redraw run under full cover, fade out 0.3s once the map reports
   idle (tiles painted). Tint = the welcome modal backdrop black. Always in
   the DOM once created, inert via opacity + pointer-events (the loadingscreen
   idiom); centred ring = the site's ONE ring, panel size (base.css). */
.map-globeswitcher-veil {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.65);
  z-index: var(--layer-sticky);
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}

.map-globeswitcher-veil--visible {
  opacity: 1;
}

.map-globeswitcher-veil--visible::after {
  --loadingring-size: 32px;
  --loadingring-thickness: 3px;
  top: 50%;
  left: 50%;
  margin: -16px 0 0 -16px;
}

.map-overlay {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  display: grid;
  place-items: center;
  color: #fff;
  font-weight: 700;
  letter-spacing: 0.5px;
  opacity: 0.15;
  pointer-events: none;
}

/* Search focus dim overlay */
.map-search-dim {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(0, 0, 0, 0);
  pointer-events: none;
  transition: background 0.25s ease;
  z-index: 1;
}

.map-search-dim--active {
  background: rgba(0, 0, 0, 0.4);
}

/* ============================================================================
   MAP CONTROLS CONTAINER
   ============================================================================ */

.map-controls {
  position: static;
  display: flex;
  width: auto;
  max-width: none;
  min-width: 0;
  z-index: auto;
  flex-wrap: nowrap;
  justify-content: center;
  align-items: center;
  box-sizing: border-box;
  opacity: 0;
}

.map-controls--in-header {
  position: static;
  left: auto;
  top: auto;
  transform: none;
  width: 100%;
  max-width: 520px;
  z-index: auto;
}

.map-controls-geocoder {
  flex: 1 1 300px;
  min-width: 0;
  width: 100%;
  max-width: 300px;
}

/* Mapbox geocoder width overrides - !important allowed */
.map-controls-geocoder-input {
  width: 100% !important;
  max-width: 300px !important;
  min-width: 0 !important;
}

@media (max-width: 530px) {
  .map-controls {
    width: auto;
    max-width: none;
    justify-content: center;
    align-items: center;
  }
  
  .map-controls:not(.map-controls--in-header) {
    width: auto;
    max-width: none;
  }
  
  .map-controls-geocoder {
    display: none;
  }
}

/* ============================================================================
   MAP CARD STYLES
   ============================================================================
   
   Map card CSS is DYNAMICALLY INJECTED by map.js injectMapMarkerStyles()
   This allows pill background images to be set from admin settings.
   
   Classes injected dynamically:
   - .map-marker-container (anchor point at lat/lng)
   - .map-marker-stamp (subcategory icon or thumbnail)
   - .map-marker-card (pill background from admin settings)
   - .map-marker-card--small, .map-marker-card--hover, .map-marker-card--big (card state variants)
   - .map-marker-labels, .map-marker-title, .map-marker-venue
   
   ============================================================================ */

/* ============================================================================
   MAP ZOOM INDICATOR
   ============================================================================ */

.map-zoom-indicator {
  position: static;
  /* Two columns: labels (left, aligned) and values (fixed-width, sized to the
     widest value "22.0", so the digits changing can never alter the pill's
     width). The pill's own 10px gap gives the 10px breathing room on each side. */
  display: grid;
  grid-template-columns: auto 28px;
  column-gap: 5px;
  row-gap: 2px;
  align-items: center;
  padding: 0;
  background: transparent;
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.3px;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  /* The zoom/pitch readout is the ONLY help target in the pill (role="button"
     in the markup). The 5px radius shapes the keyboard :focus-visible ring from
     base.css — invisible otherwise. */
  pointer-events: auto;
  cursor: help;
  border-radius: 8px;
  user-select: none;
  z-index: 5;
}
.map-zoom-indicator-label {
  text-align: left;
}
.map-zoom-indicator-value {
  text-align: left;
}

/* Map loading ring + label (operator 2026-08-12): sits where the old
   distortion notice sat — floating above the controls pill — with the site's
   ONE ring (base.css) at its default 13px on the left and "Loading Map
   Content" on the right. Text geometry and type copied verbatim from the
   deleted notice (.map-zoomwarning-text); the leading-ring row pattern from
   .fieldset-location-status.waiting (fieldsets.css). Inside the pill's own
   stacking, so no z-index is needed. */
.map-loadingring {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: 6px;
  padding-left: 21px; /* 13px ring + 8px gap */
  white-space: nowrap;
  /* Width guard (operator 2026-08-13): the label text is admin-editable
     (msg_random_load_messages), so a long line must clip with an ellipsis
     rather than overflow a narrow phone. Ellipsis trio copied from the
     postcard title (post.css ~322). */
  max-width: calc(100vw - 24px);
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
  pointer-events: none;
  display: none;
}
.map-loadingring--visible {
  display: block;
}
.map-loadingring--visible::after {
  left: 0;
  top: 50%;
  margin-top: -6.5px;
}

/* Mode-switch buttons — three always-clickable circular icon buttons (Worldwide
   / Sky / Post View) sitting inside the controls pill, to the right of the zoom
   indicator. Styled identically to the Geolocate / Compass map control buttons.
   Active vs inactive is shown by icon brightness (dim → full white), never blue,
   never greying. */
.map-modeswitch {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.map-modeswitch--hidden {
  display: none;
}
/* Circular icon buttons — identical to the map control buttons
   (.map-mapcontrol-geolocate / -compass). Inactive = dim white icon; active =
   the icon tints blue (var(--blue-500) on the currentColor mask), exactly like
   the geolocate button when it has found your location. Circle stays transparent. */
.map-modeswitch-button {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: transparent;
  border: 1px solid transparent;
  border-radius: 22px;
  padding: 0;
  margin: 0;
  cursor: pointer;
  pointer-events: auto;
  color: rgba(255, 255, 255, 0.6);
  transition: border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}
.map-modeswitch-button:hover,
.map-modeswitch-button:focus-visible {
  background-color: rgba(255, 255, 255, 0.08);
  color: #ffffff;
}
/* Active blue holds through hover/focus — only the hover background changes. */
.map-modeswitch-button--active,
.map-modeswitch-button--active:hover,
.map-modeswitch-button--active:focus-visible {
  color: var(--blue-500);
}
/* Post View button journey ring — a goToPost fly is being computed
   (map:goToPostPending). Same ring as .header-filter-badge--loading; the icon
   hides via visibility because applyModeSwitchIcons sets its opacity inline. */
.map-modeswitch-button--loading {
  position: relative;
}
.map-modeswitch-button--loading .map-modeswitch-icon {
  visibility: hidden;
}
/* Ring declared once in base.css; only the size and centring differ here. */
.map-modeswitch-button--loading::after {
  --loadingring-size: 16px;
  left: 50%;
  top: 50%;
  margin: -8px 0 0 -8px;
}
.map-modeswitch-icon {
  display: block;
  width: 30px;
  height: 30px;
  background-color: currentColor;
  /* Hidden until its mask-image is applied (applyModeSwitchIcons), so the
     unmasked currentColor box never flashes as a solid square at launch. */
  opacity: 0;
  transition: opacity 0.15s ease;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

.map-bottom-controls {
  position: absolute;
  left: 50%;
  bottom: calc(var(--safe-bottom, 0px) + 10px);
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 44px;
  padding: 2px 8px;
  border-radius: 22px;
  background: rgba(0, 0, 0, 0.45);
  z-index: var(--layer-sticky);
  transition: background 0.2s ease;
}

/* Temporary: darken the whole control pill on hover (any part of it) so it's
   clearly readable while interacting; stays subtle at rest. */
.map-bottom-controls:hover {
  background: rgba(0, 0, 0, 0.85);
}

/* ============================================================================
   MAP SCALE BAR
   ============================================================================ */

.map-scale-bar {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 300px;
  height: 30px;
  z-index: 1;
  pointer-events: none;
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
}

.map-scale-bar-line {
  position: relative;
  width: 100%;
  height: 2px;
  background: #000;
  margin-bottom: 0;
}

.map-scale-bar-mark {
  position: absolute;
  bottom: 0;
  width: 1px;
  height: 6px;
  background: #000;
}

.map-scale-bar-mark--major {
  height: 10px;
}

.map-scale-bar-label {
  position: absolute;
  bottom: 12px;
  font-size: 10px;
  color: #000;
  font-weight: 600;
  transform: translateX(-50%);
  white-space: nowrap;
}


/* ============================================================================
   UTILITY: HIDE MAP/CALENDAR
   ============================================================================ */

.map-container--hidden {
  display: none;
}

.map-calendar-container--hidden {
  display: none;
}
