/* Styles for the FBA Threat Database + Anti-Black List pages.
   Loaded in addition to the main style.css — only additive rules here. */

/* Danger level badges: green -> yellow -> orange -> red -> dark red */
.dl-badge { color: #fff; }
.dl-1 { background: #f2b8b5; }
.dl-2 { background: #e08281; }
.dl-3 { background: #c94c4c; }
.dl-4 { background: #a11d1d; }
.dl-5 { background: #5c0a0a; }

/* Operating status tags on the Anti-Black List */
.status-operating { background: #d11149; color: #fff; }
.status-shutdown { background: #666; color: #fff; }

/* Database-driven Leaflet maps */
.db-map {
  width: 100%;
  height: 340px;
  border-radius: 8px;
  margin-top: 0.5rem;
  background: #e8e8e8; /* visible placeholder while tiles load */
}
.db-map-tall { height: 70vh; min-height: 420px; }

/* --- Map loading skeleton ------------------------------------------------
   A shimmering placeholder overlay sitting on top of a map while its data
   (tiles + the GeoJSON fetch) is still loading, so a slow connection reads
   as "working" rather than "broken" or "blank." Pure CSS animation, no JS
   library -- the JS side just toggles .is-hidden once loading settles
   (success OR failure) on #fullMap (threat_map.php), #threatMap
   (threat.php), and #ablMap (antiblack.php). The map element itself
   already has a fixed height via .db-map/.db-map-tall, so wrapping both
   in a position:relative .map-container and giving the overlay inset:0
   sizes it to match exactly, with no layout shift when it's removed. */
.map-container {
  position: relative;
}

@keyframes skeleton-shimmer {
  0% { background-position: -400px 0; }
  100% { background-position: 400px 0; }
}

.skeleton-shimmer {
  background: linear-gradient(90deg, var(--surface-alt) 25%, var(--border) 37%, var(--surface-alt) 63%);
  background-size: 800px 100%;
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .skeleton-shimmer {
    animation: none;
    background: var(--surface-alt);
  }
}

.map-skeleton-overlay {
  position: absolute;
  inset: 0;
  border-radius: 8px;
  z-index: 1000; /* above Leaflet's own panes, below any real popup */
  pointer-events: none;
}

.map-skeleton-overlay.is-hidden {
  display: none;
}

/* "View in Context of Surroundings" -- a labeled Leaflet control button on
   threat.php's/antiblack.php's own small map (see the inline scripts
   there). Text button rather than an icon since there's no obvious icon
   for "show me everything nearby," styled to match .map-fullscreen-btn. */
.map-context-btn {
  background: var(--surface) !important;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  max-width: 120px;
  padding: 0.45rem 0.6rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  cursor: pointer;
  color: var(--heading);
  font-weight: 700;
  font-size: 0.78rem;
  line-height: 1.25;
}

.map-context-btn:hover {
  background: var(--primary-soft) !important;
  color: var(--primary-dark);
  border-color: var(--primary);
}

.map-context-btn[disabled] {
  cursor: default;
  opacity: 0.75;
  pointer-events: none;
}

/* Leaflet's own CSS gives its zoom controls z-index: 1000 and its popups
   z-index: 700 -- those values are only meant to order things WITHIN the
   map. Without a map container that establishes its own stacking context,
   those numbers compete directly with the rest of the page instead, which
   is how the sticky site header (z-index: 40) was ending up rendered
   BEHIND the map's zoom buttons while scrolling. isolation: isolate boxes
   all of Leaflet's internal z-index values inside the map element, so
   nothing it does can ever climb above page chrome like the header again.
   Deliberately NOT also setting position:relative here -- Leaflet sets
   that on its own container at runtime, and adding it again in CSS turns
   this whole box into a "positioned" element in its OWN right. Since the
   map sits later in the page than the sticky header, that made the
   entire map (not just its internal controls) paint on top of the
   header instead of under it -- isolation alone gives the containment
   without that side effect. */
.db-map,
#routeMap {
  isolation: isolate;
}

/* Danger level legend on the full map page */
.dl-legend { display: flex; flex-wrap: wrap; gap: 0.75rem; margin: 0.5rem 0; }
.dl-legend-item { display: inline-flex; align-items: center; gap: 0.3rem; }
.dl-swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 3px;
}

/* Draw-a-map box on add/edit threat and Anti-Black List forms */
#drawMap { height: 420px; border-radius: 8px; margin-top: 0.5rem; background: #e8e8e8; }
.map-help { font-size: 0.85rem; color: #5b6b7f; margin-top: 0.4rem; }

/* --- Full map page (threat_map.php) -------------------------------------
   Previously lived as an inline <style nonce> block on the old admin-only
   Leaflet map page -- that doesn't work under this site's CSP
   (style-src 'self', no nonce allowance for styles), so none of it was
   actually rendering. Moved here as real external CSS, now that this map
   is the main public map page, and reskinned with the site's own red
   palette instead of the old hardcoded admin-tool colors. */
.map-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
  padding: 0.6rem 0.8rem;
  width: 260px;
  box-sizing: border-box;
  font-size: 0.9rem;
}

.map-panel input[type="text"] {
  width: 100%;
  min-height: 42px;
  margin-bottom: 0;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
}

.map-search-results {
  max-height: 220px;
  overflow-y: auto;
  margin-top: 0.4rem;
}

.map-search-results:empty {
  margin-top: 0;
  max-height: 0;
}

.map-search-results > div {
  padding: 0.4rem 0.5rem;
  border-radius: 6px;
  font-size: 0.9rem;
  cursor: pointer;
}

.map-search-results > div:hover {
  background: var(--primary-soft);
}

.map-panel-divider {
  border-top: 1px solid var(--border);
  margin: 0.6rem 0;
}

/* Minimize button for the search/filters panel -- shown at EVERY screen
   size now, not just phones (it used to be mobile-only, which left
   tablet and desktop stuck with no way to shrink this panel even though
   it's exactly as capable of covering a big share of the map there).
   Starts open everywhere except phone-sized screens (see the JS, which
   checks the same 640px cutoff used below) -- collapsing it is always a
   deliberate tap, never something sprung on a desktop visitor who's used
   to seeing the filters immediately. */
.map-panel-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: 38px;
  padding: 0.5rem 0.7rem;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--surface-alt);
  color: var(--heading);
  font-weight: 700;
  font-size: 0.9rem;
  cursor: pointer;
}

.map-panel.is-open .map-panel-toggle {
  margin-bottom: 0.5rem;
}

/* Collapsed state is now the universal "hidden" rule (not nested inside
   the phone-only media query below), so the minimize button actually
   does something at every screen width. */
.map-panel-body {
  display: none;
  max-height: min(60vh, 420px);
  overflow-y: auto;
}

.map-panel.is-open .map-panel-body {
  display: block;
}

@media (max-width: 640px) {
  .map-panel {
    width: auto;
    max-width: min(260px, calc(100vw - 2.5rem));
  }
}

.map-filters-wrap {
  background: var(--surface-alt);
  border-radius: var(--radius-sm);
  padding: 0.6rem 0.7rem;
}

.map-filter-group { margin-bottom: 0.6rem; }
.map-filter-group:last-child { margin-bottom: 0; }
.map-filter-group > label { font-weight: 700; display: flex; align-items: center; gap: 0.5rem; color: var(--heading); }
.map-filter-sub { margin-left: 1.6rem; margin-top: 0.35rem; display: flex; flex-direction: column; gap: 0.3rem; }
.map-filter-sub label { display: flex; align-items: center; gap: 0.5rem; font-weight: 400; }

input.fba-checkbox {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  display: inline-block;
  width: 20px;
  height: 20px;
  min-width: 20px;
  min-height: 20px;
  box-sizing: border-box;
  border: 2px solid var(--border-strong);
  border-radius: 4px;
  background-color: var(--surface);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 13px 13px;
  cursor: pointer;
  margin: 0;
  padding: 0;
  outline: none;
}
input.fba-checkbox:checked {
  background-color: var(--primary);
  border-color: var(--primary);
  background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='white' d='M13.485 1.929a1 1 0 010 1.414L6.414 10.414a1 1 0 01-1.414 0L2.515 7.929a1 1 0 111.414-1.414L5.707 8.293l6.364-6.364a1 1 0 011.414 0z'/%3E%3C/svg%3E");
}
input.fba-checkbox:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.map-choose-popup { max-width: 240px; }
.map-choose-popup .choose-msg { font-size: 0.85em; color: var(--muted); margin-bottom: 6px; }
.map-choose-popup .choose-item {
  display: block;
  color: var(--primary);
  text-decoration: underline;
  font-weight: 700;
  cursor: pointer;
  padding: 3px 0;
}
.map-choose-popup .choose-item:hover { color: var(--primary-dark); }

.map-popup-name { font-size: 1.1em; }
.map-popup-address,
.map-popup-desc { font-size: 0.85em; color: var(--muted); margin-top: 2px; }
.map-popup-link { margin-top: 4px; }

.map-fullscreen-btn {
  background: var(--surface) !important;
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  cursor: pointer;
  color: var(--heading);
}

/* Near Me -- deliberately a small, understated icon-only control in its
   own corner rather than a labeled button competing with the search
   panel for attention. */
.map-near-me-wrap {
  position: relative;
}

.map-near-me-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  min-height: 34px;
  padding: 0;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--muted);
  box-shadow: var(--shadow);
}

.map-near-me-icon-btn:hover {
  background: var(--primary-soft);
  color: var(--primary-dark);
  border-color: var(--primary);
}

.map-near-me-icon-btn svg {
  width: 18px;
  height: 18px;
}

.map-near-me-status {
  position: absolute;
  right: 0;
  bottom: calc(100% + 0.4rem);
  width: 200px;
  margin: 0;
  padding: 0.5rem 0.7rem;
  border-radius: var(--radius-sm);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  font-size: 0.8rem;
  color: var(--muted);
}

.user-location-marker { position: relative; }

.user-location-dot {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  background: var(--primary);
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}

.user-location-pulse {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 22px;
  height: 22px;
  margin: -11px 0 0 -11px;
  border-radius: 50%;
  background: var(--primary);
  opacity: 0.35;
  animation: user-location-pulse 1.8s ease-out infinite;
}

@keyframes user-location-pulse {
  0% { transform: scale(0.5); opacity: 0.45; }
  100% { transform: scale(1.8); opacity: 0; }
}

/* --- "Found this helpful?" feedback widget (threat.php) ---------------- */

.feedback-widget {
  margin-top: 1.25rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-alt);
}

.feedback-prompt {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
}

.feedback-label {
  font-weight: 650;
  color: var(--text);
  margin-right: 0.2rem;
}

.feedback-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 34px;
  padding: 0.35rem 0.85rem;
  font-size: 0.85rem;
  font-weight: 650;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
}

/* Three distinct, deliberate states -- not voted yet / hovering / voted:
     - resting (not voted):  white  (.feedback-btn's own background above)
     - hover   (not voted):  light red
     - voted   (is-active):  dark red, whichever button (up or down) you
                              actually picked -- both read the same "this
                              is your answer" dark red rather than down
                              getting a different, unrelated gray.

   The site-wide `button:hover` rule in style.css (background:
   var(--primary-dark) + a red glow) has higher CSS specificity than our
   plain `.feedback-btn` class, so without an explicit override here it
   wins the instant you hover *any* feedback button. The
   `button.feedback-btn...` (element + class) form below is deliberate,
   not just style: it's what makes these rules beat BOTH that site-wide
   rule AND `.feedback-btn-up/down.is-active` below, which would
   otherwise share the exact same two-class specificity as a plain
   `.feedback-btn:hover`/`:is-active` tie -- and specifically, it's what
   keeps hover on a voted button still reading as hover-over-dark-red
   rather than snapping back to the light-red hover color. */
button.feedback-btn:hover {
  background: var(--primary-soft);
  color: var(--primary-dark);
  border-color: var(--border-strong);
  box-shadow: none;
}

button.feedback-btn:active {
  background: var(--primary-dark);
  color: #fff;
  border-color: var(--primary-dark);
  box-shadow: none;
}

.feedback-btn:disabled {
  opacity: 0.6;
  cursor: default;
}

button.feedback-btn:disabled:hover,
button.feedback-btn:disabled:active {
  background: var(--surface);
  color: var(--muted);
  border-color: var(--border);
}

.feedback-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  fill: #1a1a1a;
  stroke: #8a8a8a;
  stroke-width: 0.5;
  filter: drop-shadow(0 1px 1px rgba(90, 90, 90, 0.5));
}

.feedback-btn-up.is-active,
.feedback-btn-down.is-active {
  background: var(--primary-dark);
  color: #fff;
  border-color: var(--primary-dark);
}

/* On the dark red "voted" background, the black icon from the rule above
   needs to flip to white to stay visible -- its gray outline/shadow would
   otherwise vanish against the dark fill. */
.feedback-btn-up.is-active .feedback-icon,
.feedback-btn-down.is-active .feedback-icon {
  fill: #fff;
  stroke: rgba(255, 255, 255, 0.65);
  filter: none;
}

/* Hovering an already-voted button should still read as dark red, not
   fade back to the lighter "not voted yet" hover color -- same
   element+class specificity trick as button.feedback-btn:hover above,
   so this wins the tie against it. */
button.feedback-btn-up.is-active:hover,
button.feedback-btn-down.is-active:hover {
  background: var(--primary-dark);
  color: #fff;
  border-color: var(--primary-dark);
}

.feedback-thanks,
.feedback-suggest {
  margin: 0.6rem 0 0;
}

@media (max-width: 480px) {
  .feedback-prompt {
    gap: 0.5rem;
  }
}

/* Plan A Route's own map (route_planner.php). This used to be sized with
   inline style="" attributes directly in the HTML instead of a class like
   .db-map/.db-map-tall above -- which silently never applied, because
   this site's CSP sends "style-src 'self'" with no 'unsafe-inline' and
   (per the CSP spec) a nonce/hash doesn't cover style attributes at all.
   So the browser was correctly blocking that inline style as a security
   measure, #routeMap rendered at its default 0 height, and the Leaflet
   map -- which WAS initializing correctly underneath -- had nowhere
   visible to draw into. Moving the sizing into the stylesheet (exactly
   like every other map on the site already does) fixes it, since
   'self' stylesheets were never restricted. */
.route-map-container {
  margin: 1rem 0;
}

#routeMap {
  height: 420px;
  border-radius: var(--radius);
}

#routeMapSkeleton {
  border-radius: var(--radius);
}

/* --- API usage dashboard (admin_api_usage.php, admin-only) -------------
   A plain div-based progress bar rather than <progress> -- easier to
   color by threshold (ok/warn/crit) with a single class swap, and no
   cross-browser default-styling fight. Colors reuse tokens already used
   elsewhere on the site (.good's green, dl-4's red) plus one new amber
   for the "getting close" middle state, since nothing amber existed
   anywhere else on this site to reuse. */
.usage-bar-track {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 999px;
  height: 14px;
  overflow: hidden;
  margin: 0.4rem 0;
}

.usage-bar-fill {
  height: 100%;
  border-radius: 999px 0 0 999px;
}

.usage-bar-fill.usage-ok { background: #1e6a34; }
.usage-bar-fill.usage-warn { background: #c77d00; }
.usage-bar-fill.usage-crit { background: #a11d1d; }

.usage-bar-label {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}
