/* =============================================================================
   Travel Custom Maps — Frontend CSS (tcm-frontend.css)
   Styles for: map wrap, GDPR gate, offline bar, layer panel, filter strip,
   marker icons, cluster badges, popup/infowindow, bottom sheet, loading overlay.
   ============================================================================= */

/* ── CSS Variables ───────────────────────────────────────────────────────────── */
:root {
  --tcm-blue:       #2563eb;
  --tcm-blue-dark:  #1d4ed8;
  --tcm-green:      #16a34a;
  --tcm-red:        #dc2626;
  --tcm-amber:      #d97706;
  --tcm-white:      #ffffff;
  --tcm-surface:    rgba(255,255,255,.96);
  --tcm-shadow:     0 4px 24px rgba(0,0,0,.14);
  --tcm-radius:     12px;
  --tcm-radius-sm:  8px;
  --tcm-font:       -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', sans-serif;
  --tcm-transition: 200ms cubic-bezier(.4,0,.2,1);
}

/* ── Map Wrap ────────────────────────────────────────────────────────────────── */
.tcm-map-wrap {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 500px !important;
  font-family: var(--tcm-font);
  border-radius: var(--tcm-radius);
  box-shadow: 0 2px 16px rgba(0,0,0,.12);
  background: #e8edf2;
  margin: 1em 0;
}

.tcm-map-canvas {
  position: relative;
  width: 100% !important;
  height: 500px !important;
  min-height: 450px !important;
  display: block !important;
  visibility: visible !important;
  opacity: 1 !important;
  z-index: 10;
  background: #e8edf2;
  pointer-events: all;
}

/* Ensure Leaflet z-index stays inside our wrap */
.tcm-map-wrap .leaflet-pane         { z-index: 1; }
.tcm-map-wrap .leaflet-control-zoom { z-index: 10; }
.tcm-map-wrap .leaflet-control-attribution { font-size: 10px; }

/* ── GDPR Gate ───────────────────────────────────────────────────────────────── */
.tcm-gdpr-gate {
  position: absolute;
  inset: 0;
  /* Above every Leaflet pane (max ~700) and above our own controls, so no
     stacking context on the page can surface a control through the glass. */
  z-index: 10001 !important;
  display: flex;
  align-items: center;
  justify-content: center;

  /* THE GLASS SHEET.
     The tint arrives pre-composited as one rgba() value; using the opacity
     property instead would fade the message box and button along with it.
     The blur is what makes the live map read as "present but locked" rather
     than "not loaded yet". */
  background: var(--tcm-gdpr-overlay, rgba(15, 23, 42, .55));
  -webkit-backdrop-filter: blur(5px) saturate(115%);
  backdrop-filter: blur(5px) saturate(115%) !important;

  /* The sheet never intercepts input. Interaction is frozen by disabling
     Leaflet's own handlers (see setMapInteraction in tcm-map.js), which is
     more reliable than swallowing events here — a swallowing overlay still
     leaks wheel and touch gestures on some mobile browsers. */
  pointer-events: none !important;

  opacity: 1;
  transition: opacity .3s ease, backdrop-filter .3s ease;
}

/* Browsers without backdrop-filter get a heavier tint so the message stays
   readable instead of sitting on an unblurred map. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .tcm-gdpr-gate {
    background: var(--tcm-gdpr-overlay, rgba(15, 23, 42, .82));
  }
}

/* Fade-out state applied by release() before the node is removed. */
.tcm-gdpr-gate.is-dismissed {
  opacity: 0;
  -webkit-backdrop-filter: blur(0);
  backdrop-filter: blur(0) !important;
}

.tcm-gdpr-gate__inner {
  /* The parent is pointer-events:none, so the box must opt back in or the
     accept button would be unclickable. */
  pointer-events: auto !important;

  background: var(--tcm-gdpr-box, #fff);
  color: var(--tcm-gdpr-text, #374151);
  border-radius: var(--tcm-gdpr-radius, 14px);
  padding: 36px 28px;
  max-width: 400px;
  text-align: center;
  box-shadow: var(--tcm-shadow);
}
.tcm-gdpr-gate__inner.no-shadow { box-shadow: none; }
.tcm-gdpr-gate__icon { font-size: 40px; margin-bottom: 12px; }
.tcm-gdpr-gate__text {
  font-size: 15px;
  color: var(--tcm-gdpr-text, #374151);
  margin-bottom: 20px;
  line-height: 1.5;
}
.tcm-gdpr-gate .tcm-gdpr-accept {
  pointer-events: auto !important;
  background: var(--tcm-gdpr-btn-bg, var(--tcm-blue)) !important;
  color: var(--tcm-gdpr-btn-fg, #fff) !important;
  border-radius: var(--tcm-gdpr-btn-radius, 8px) !important;
  border: none !important;
  cursor: pointer;
}

/* While the shroud is up the canvas must not show a grab cursor, which would
   advertise a drag that has been deliberately disabled. */
.tcm-map-wrap:has(> .tcm-gdpr-gate) .leaflet-container,
.tcm-map-canvas-wrap:has(> .tcm-gdpr-gate) .leaflet-container {
  cursor: default !important;
}

/* ── Route direction arrows ──────────────────────────────────────────────────
   Rotation is applied to an inner span, never to the Leaflet marker element
   itself: Leaflet writes its own transform there for positioning, and adding
   ours would fight it and detach the glyph from the line.
   ─────────────────────────────────────────────────────────────────────────── */
.tcm-route-arrow {
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
}
.tcm-route-arrow__glyph {
  display: block;
  font-size: 15px;
  line-height: 1;
  transform-origin: center center;
  text-shadow: 0 0 3px rgba(255,255,255,.9), 0 0 2px rgba(255,255,255,.9);
  pointer-events: none;
  user-select: none;
}

/* ── Layer Panel ─────────────────────────────────────────────────────────────── */
.tcm-layer-panel {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 800;
  background: var(--tcm-surface);
  border-radius: var(--tcm-radius-sm);
  box-shadow: var(--tcm-shadow);
  min-width: 200px;
  max-width: 280px;
  width: max-content;
  overflow: hidden;
  backdrop-filter: blur(10px);
}

.tcm-layer-panel__toggle {
  display: flex !important;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 11px 14px;
  background: #ffffff !important;
  color: #1e293b !important;
  font-size: 13px;
  font-weight: 600;
  border: none !important;
  cursor: pointer;
  text-align: left;
  transition: background var(--tcm-transition);
  box-sizing: border-box;
  outline: none;
}

.tcm-layer-panel__toggle:hover,
.tcm-layer-panel__toggle:active,
.tcm-layer-panel__toggle:focus {
  background: #f1f5f9 !important;
  color: #1e293b !important;
}

.tcm-toggle-icon {
  margin-left: auto;
  font-size: 10px;
  color: #64748b;
  transition: transform var(--tcm-transition);
}

.tcm-layer-panel__body {
  display: none;
  flex-direction: column;
  max-height: 320px;
  overflow-y: auto;
  padding: 6px 0 10px;
  border-top: 1px solid rgba(0,0,0,.07);
}

.tcm-layer-panel__body--open {
  display: flex !important;
}

.tcm-layer-group {
  padding: 0 10px 4px;
}

.tcm-layer-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 4px;
  font-size: 13px;
  font-weight: 600;
  color: #334155;
  cursor: pointer;
  border-radius: 6px;
  transition: background var(--tcm-transition);
  user-select: none;
}

.tcm-layer-header:hover {
  background: rgba(0,0,0,.05);
  color: #0f172a;
}

.tcm-layer-cb,
.tcm-layer-cb-all {
  width: 15px;
  height: 15px;
  cursor: pointer;
  flex-shrink: 0;
  accent-color: var(--tcm-blue);
}

.tcm-layer-icon {
  width: 18px;
  height: 18px;
  object-fit: contain;
  flex-shrink: 0;
}

.tcm-layer-title {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Sub-location items */
.tcm-layer-items {
  list-style: none;
  padding: 0;
  margin: 0 0 4px 28px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.tcm-layer-item {
  display: flex;
  align-items: center;
}

.tcm-item-link {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px;
  font-size: 12.5px;
  color: #475569;
  text-decoration: none;
  border-radius: 5px;
  transition: background var(--tcm-transition), color var(--tcm-transition);
  width: 100%;
}

.tcm-item-link:hover {
  background: rgba(37,99,235,.08);
  color: #1e40af;
}

.tcm-item-icon { flex-shrink: 0; display: flex; }
.tcm-item-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.tcm-item--hidden { display: none !important; }
.tcm-layer-items--expanded .tcm-item--hidden { display: flex !important; }

.tcm-layer-more {
  display: block;
  margin: 2px 0 0 28px;
  padding: 3px 6px;
  background: none;
  border: none;
  font-size: 11.5px;
  color: var(--tcm-blue);
  cursor: pointer;
  font-weight: 500;
}
.tcm-layer-more:hover { text-decoration: underline; }

/* ── Map Style Switcher ───────────────────────────────────────────────────────── */
.tcm-style-switcher {
  position: absolute;
  bottom: 24px;
  left: 12px;
  z-index: 800;
}

.tcm-style-switcher__toggle {
  width: 40px;
  height: 40px;
  background: #ffffff !important;
  border-radius: var(--tcm-radius-sm);
  box-shadow: var(--tcm-shadow);
  display: flex !important;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border: 1.5px solid #1e293b !important;
  padding: 0;
  transition: all var(--tcm-transition);
  color: #1e293b !important;
}

.tcm-style-switcher__toggle:hover,
.tcm-style-switcher__toggle:active,
.tcm-style-switcher__toggle:focus {
  background: #1e293b !important;
  color: #ffffff !important;
}

.tcm-style-switcher__menu {
  display: none;
  position: absolute;
  bottom: 48px;
  left: 0;
  flex-direction: column;
  background: var(--tcm-surface);
  border-radius: var(--tcm-radius-sm);
  box-shadow: var(--tcm-shadow);
  padding: 6px;
  gap: 2px;
  min-width: 148px;
  backdrop-filter: blur(10px);
}

.tcm-style-btn {
  display: block;
  width: 100%;
  padding: 8px 12px;
  background: transparent !important;
  border: 1px solid transparent !important;
  color: #1e293b !important;
  font-size: 13px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  border-radius: 5px;
  transition: background var(--tcm-transition);
  white-space: nowrap;
}

.tcm-style-btn:hover,
.tcm-style-btn:focus,
.tcm-style-btn--active {
  background: #1e293b !important;
  color: #ffffff !important;
  border-color: #1e293b !important;
}

/* ── Offline Footer ───────────────────────────────────────────────────────────
   The bar sits BELOW the map canvas as a standalone element. It carries no
   surface of its own — no background, no border, no padding box — so nothing
   grey can bleed around the button. `isolation: isolate` plus a top-of-stack
   z-index keeps it above any theme overlay that would otherwise swallow
   pointer events over the button's upper portion.
   ───────────────────────────────────────────────────────────────────────────── */
.tcm-offline-footer,
.tcm-offline-bar {
  width: auto !important;
  max-width: 100% !important;
  background: none !important;
  background-color: transparent !important;
  border: none !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  outline: none !important;
  padding: 0 !important;
  margin: 10px auto 20px !important;
  clear: both !important;
  display: flex !important;
  justify-content: center !important;
  align-items: center !important;
  box-sizing: border-box !important;
  overflow: visible !important;
  position: relative !important;
  isolation: isolate;
  z-index: 9999 !important;
  pointer-events: auto !important;
}

/* ─────────────────────────────────────────────────────────────────────────────
   GHOST TRACKER
   A 24px-wide invisible twin of each trail, carrying the click and hover
   events so a 3px line becomes an easy target. opacity:0 rather than
   visibility/display, because a hidden element receives no pointer events at
   all and the whole point is to receive them.
   ────────────────────────────────────────────────────────────────────────────── */
.leaflet-interactive.tcm-ghost-tracker {
  opacity: 0 !important;
  stroke-opacity: 0 !important;
  fill-opacity: 0 !important;
  stroke-width: 24px !important;
  stroke-linecap: round !important;
  stroke-linejoin: round !important;
  cursor: pointer !important;
  pointer-events: stroke !important;
}

/* ─────────────────────────────────────────────────────────────────────────────
   OFFLINE BUTTON AUTO-RESET
   The confirmation state fades back to the default after 3 seconds.
   ────────────────────────────────────────────────────────────────────────────── */
.tcm-offline-btn {
  transition: background-color .25s ease, color .25s ease,
              border-color .25s ease, opacity .25s ease;
}
.tcm-offline-btn.is-fading {
  opacity: .35;
  /* Belt and braces for the auto-reset transition on every pointer type. */
  outline: none !important;
  box-shadow: none !important;
}

/* ─────────────────────────────────────────────────────────────────────────────
   GREY HAIRLINE PURGE above the standalone offline pill.
   Our own stylesheet defines no border there — the offline footer already
   carries `border: none !important`. The visible hairline therefore comes from
   the THEME: a separator applied to the block wrapper, to the map wrap's
   bottom edge, or to the adjacent-sibling boundary. These rules remove every
   plausible source so the pill floats completely free.
   ───────────────────────────────────────────────────────────────────────────── */
.tcm-offline-footer,
.tcm-offline-bar,
.tcm-offline-footer *,
.tcm-offline-bar > * {
  border-top: 0 !important;
  border-block-start: 0 !important;
  box-shadow: none !important;
}

/* The element immediately preceding the pill must not draw a bottom edge. */
.tcm-map-wrap {
  border-bottom: 0 !important;
  border-block-end: 0 !important;
}
.tcm-map-wrap + .tcm-offline-footer,
.tcm-map-wrap + .tcm-offline-bar {
  border-top: 0 !important;
  border-block-start: 0 !important;
  margin-top: 10px !important;
}

/* Some themes hang a separator off the wrapper rather than off either child. */
.tcm-map-wrap::after,
.tcm-map-wrap + .tcm-offline-footer::before,
.tcm-map-wrap + .tcm-offline-bar::before {
  content: none !important;
  display: none !important;
  border: 0 !important;
}

/* ─────────────────────────────────────────────────────────────────────────────
   MOBILE ONE-FINGER GESTURE HINT
   Shown while a single finger is on the canvas; the document scrolls normally
   underneath it. pointer-events:none is essential — the hint must never eat
   the very gesture it is describing.
   ───────────────────────────────────────────────────────────────────────────── */
.tcm-gesture-hint {
  position: absolute;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none !important;
  background: rgba(15, 23, 42, .55);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  opacity: 0;
  visibility: hidden;
  transition: opacity .18s ease, visibility .18s ease;
}
.tcm-gesture-hint.is-visible {
  opacity: 1;
  visibility: visible;
}
.tcm-gesture-hint__text {
  display: block;
  max-width: 78%;
  padding: 14px 20px;
  border-radius: 12px;
  background: rgba(0, 0, 0, .72);
  color: #fff;
  font-family: var(--tcm-font);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.45;
  text-align: center;
  direction: rtl;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
}

/* The consent shroud outranks the gesture hint — consent comes first. */
.tcm-gdpr-gate ~ .tcm-gesture-hint { display: none !important; }

/* ─────────────────────────────────────────────────────────────────────────────
   CLUSTER PROXY
   A zero-size invisible marker standing in for a trail or area inside the
   cluster engine. It must occupy no space and paint nothing, but stay
   clickable so tapping the collapsed cluster still reaches the shape.
   ───────────────────────────────────────────────────────────────────────────── */
.tcm-cluster-proxy {
  width: 0 !important;
  height: 0 !important;
  background: none !important;
  border: 0 !important;
  box-shadow: none !important;
  opacity: 0 !important;
}

/* ─────────────────────────────────────────────────────────────────────────────
   MOBILE POPUP PARITY
   The mobile bottom sheet is gone; phones now render the same floating card
   as desktop. These rules stop Leaflet's own mobile sizing from re-creating
   the clipped, transparent corner box.
   ───────────────────────────────────────────────────────────────────────────── */
/* ─────────────────────────────────────────────────────────────────────────────
   POPUP GEOMETRY
   The squishing came from Leaflet computing its own content width against a
   wrapper with no width floor. A theme rule that narrows .leaflet-popup-content
   then collapses the card into a column a few characters wide. min-width puts
   a hard floor under it and max-width stops it sprawling.
   ────────────────────────────────────────────────────────────────────────────── */
.tcm-popup-wrap .leaflet-popup-content-wrapper {
  background: #fff !important;
  border-radius: var(--tcm-radius, 12px) !important;
  box-shadow: 0 8px 28px rgba(0, 0, 0, .28) !important;
  padding: 0 !important;
  overflow: hidden !important;
  width: auto !important;
  min-width: 280px !important;
  max-width: 340px !important;
}
.tcm-popup-wrap .leaflet-popup-content {
  margin: 0 !important;
  width: auto !important;
  min-width: 280px !important;
  max-width: 340px !important;
  /* Long unbroken URLs used to force the card wider than its own max-width. */
  overflow-wrap: anywhere;
  word-break: normal;
}
.tcm-popup-wrap .leaflet-popup-tip {
  background: #fff !important;
  box-shadow: none !important;
}

/* ─────────────────────────────────────────────────────────────────────────────
   POPUP TEXT ALIGNMENT
   The three custom properties are written inline by tcm-popup.js from the map
   setting and the location override. 'auto' is resolved to a concrete side in
   JS — `text-align: auto` is not a real value and would silently fall back to
   the theme default, which is what forced Hebrew content to read LTR.
   ────────────────────────────────────────────────────────────────────────────── */
.tcm-popup-align {
  direction: var(--tcm-popup-dir, ltr);
}
.tcm-popup-align .tcm-popup__title {
  text-align: var(--tcm-align-title, start) !important;
}
.tcm-popup-align .tcm-popup__address,
.tcm-popup-align .tcm-popup__teaser,
.tcm-popup-align .tcm-popup__body p {
  text-align: var(--tcm-align-body, start) !important;
}
/* The button is inline-block, so its own text-align does nothing — the
   PARENT's alignment is what positions it within the card. */
.tcm-popup-align .tcm-popup__body {
  text-align: var(--tcm-align-button, start);
}
.tcm-popup-align .tcm-popup__btn {
  display: inline-block;
  text-align: center !important;
}

@media (max-width: 767px) {
  .tcm-popup-wrap--mobile .leaflet-popup-content-wrapper,
  .tcm-popup-wrap--mobile .leaflet-popup-content {
    /* Never wider than the screen, and never a hairline sliver either. */
    max-width: calc(100vw - 40px) !important;
    min-width: min(280px, calc(100vw - 40px)) !important;
  }
  .tcm-popup-wrap--mobile .leaflet-popup-content {
    max-height: 62vh !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
  }
  /* Leaflet gives the close button a 24px hit area; a thumb needs more. */
  .tcm-popup-wrap--mobile .leaflet-popup-close-button {
    width: 34px !important;
    height: 34px !important;
    font-size: 22px !important;
    line-height: 32px !important;
  }
  /* The close button must follow the reading direction, not sit on top of
     the title in RTL. */
  .tcm-popup-align[style*="rtl"] ~ * .leaflet-popup-close-button,
  .leaflet-popup-content:has(.tcm-popup-align[style*="rtl"]) .leaflet-popup-close-button {
    right: auto !important;
    left: 0 !important;
  }
}

/* ─────────────────────────────────────────────────────────────────────────────
   ADMIN-SIDE VERTEX SELECTOR helpers live in admin.css; these are the
   front-end-only rules.
   ────────────────────────────────────────────────────────────────────────────── */

/* Kill any inherited pseudo-element artifacts from aggressive themes */
.tcm-offline-footer::before,
.tcm-offline-footer::after,
.tcm-offline-bar::before,
.tcm-offline-bar::after {
  content: none !important;
  display: none !important;
}

.tcm-offline-footer .tcm-offline-btn,
.tcm-offline-bar .tcm-offline-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.tcm-offline-btn {
  position: relative !important;
  z-index: 9999 !important;
  pointer-events: auto !important;
  touch-action: manipulation;
  background: transparent !important;
  color: #1e293b !important;
  border: 1.5px solid #64748b !important;
  border-radius: 20px;
  padding: 8px 20px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: all var(--tcm-transition);
  line-height: 1.4;
}

/* ─────────────────────────────────────────────────────────────────────────────
   STICKY TOUCH :HOVER TRAP
   A touchscreen has no pointer to move away, so the browser leaves the last
   tapped element in :hover until something else is tapped — the button stays
   locked in its dark hover colour after the finger lifts.

   The cure is to make the hover rule unreachable on touch rather than to try
   to undo it afterwards: @media (hover: hover) matches only devices that can
   genuinely hover. Coarse pointers get :active instead, which ends the moment
   the finger lifts.
   ───────────────────────────────────────────────────────────────────────────── */
@media (hover: hover) and (pointer: fine) {
  .tcm-offline-btn:hover,
  .tcm-offline-footer button:hover,
  .tcm-offline-bar button:hover {
  background: #1e293b !important;
  color: #ffffff !important;
  border-color: #1e293b !important;
}
}

/* Coarse pointers: a brief press state that cannot stick, plus an explicit
   reset of every property the hover rule would have set. */
@media (hover: none), (pointer: coarse) {
  /* Safari and Chrome paint a translucent blue box on tap unless told not to;
     that is the blue "blip" that appears before any CSS state applies. */
  .tcm-offline-btn,
  .tcm-offline-footer button,
  .tcm-offline-bar button {
    -webkit-tap-highlight-color: transparent !important;
    tap-highlight-color: transparent !important;
  }

  /* :focus is the OTHER half of the sticky trap. A tapped button keeps focus
     after the finger lifts, so a :focus rule locks the colour just as firmly
     as :hover did. :focus-visible is left alone — keyboard users still need
     a ring. */
  /* The blue skin during the 3-second auto-reset was the FOCUS ring, not a
     background: the button still holds focus from the original tap, so the
     UA default focus outline / box-shadow repaints as the inline styles are
     cleared. All three are killed together. */
  .tcm-offline-btn:focus,
  .tcm-offline-btn:focus-visible,
  .tcm-offline-btn:focus-within,
  .tcm-offline-btn:active,
  .tcm-offline-btn:-webkit-any-link,
  .tcm-offline-footer button:focus,
  .tcm-offline-footer button:focus-visible,
  .tcm-offline-footer button:focus-within,
  .tcm-offline-footer button:active,
  .tcm-offline-footer a:-webkit-any-link,
  .tcm-offline-bar button:focus,
  .tcm-offline-bar button:focus-visible,
  .tcm-offline-bar button:focus-within,
  .tcm-offline-bar button:active,
  .tcm-offline-bar a:-webkit-any-link {
    outline: none !important;
    outline-offset: 0 !important;
    box-shadow: none !important;
    -webkit-tap-highlight-color: transparent !important;
    -webkit-focus-ring-color: transparent !important;
    /* Suppresses the long-press callout sheet, which on iOS paints its own
       selection tint over the button while the finger is held. */
    -webkit-touch-callout: none !important;
    -webkit-user-select: none !important;
    user-select: none !important;
  }

  .tcm-offline-btn:hover,
  .tcm-offline-btn:focus,
  .tcm-offline-btn:focus-within,
  .tcm-offline-footer button:hover,
  .tcm-offline-footer button:focus,
  .tcm-offline-bar button:hover,
  .tcm-offline-bar button:focus {
    background: var(--tcm-blue, #2563eb) !important;
    color: #fff !important;
    transform: none !important;
    box-shadow: 0 2px 8px rgba(37, 99, 235, .25) !important;
  }

  /* Press feedback is a neutral grey, not a blue that could be mistaken for
     the sticky state being reported. */
  .tcm-offline-btn:active,
  .tcm-offline-footer button:active,
  .tcm-offline-bar button:active {
    background: #e2e8f0 !important;
    color: #0f172a !important;
    transform: scale(.97) !important;
    transition: transform .08s ease, background-color .08s ease !important;
  }

  /* Caching in progress: the same neutral grey, held. */
  .tcm-offline-btn:disabled:not(.tcm-offline-btn--saved),
  .tcm-offline-btn[disabled]:not(.tcm-offline-btn--saved) {
    background: #e2e8f0 !important;
    color: #475569 !important;
    opacity: 1 !important;
  }

  /* The saved state must still win over both of the above. */
  .tcm-offline-btn.tcm-offline-btn--saved,
  .tcm-offline-btn.tcm-offline-btn--saved:hover,
  .tcm-offline-btn.tcm-offline-btn--saved:active {
    background: #22c55e !important;
    color: #fff !important;
    transform: none !important;
  }
}


.tcm-offline-btn--saved {
  background: #16a34a !important;
  color: #ffffff !important;
  border-color: #16a34a !important;
}

/* ── Loading Overlay ─────────────────────────────────────────────────────────── */
.tcm-loading-overlay {
  position: absolute;
  inset: 0;
  z-index: 900;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(255,255,255,.55);
  backdrop-filter: blur(3px);
}

.tcm-spinner {
  width: 36px;
  height: 36px;
  border: 4px solid #e2e8f0;
  border-top-color: var(--tcm-blue);
  border-radius: 50%;
  animation: tcm-spin .75s linear infinite;
}

@keyframes tcm-spin { to { transform: rotate(360deg); } }

/* ─────────────────────────────────────────────────────────────────────────────
   Block containment shell

   Absorbed from the theme's former "map sandbox" wrapper. The map now bounds
   itself, so it works identically under any theme and there is no second
   layout layer to keep in sync.

   `isolation: isolate` opens a local stacking context, which is what keeps the
   layer panel and offline bar above the canvas without leaking z-index into
   the host theme. No viewport-relative negative margins are used anywhere —
   those were what pushed the map past the container edge and hid the layer
   panel off-screen.
   ───────────────────────────────────────────────────────────────────────────── */
.tcm-block-shell {
  position: relative;
  isolation: isolate;
  z-index: 1;
  width: 100%;
  max-width: 100%;
  margin-inline: 0;
  overflow: visible;
}

.tcm-block-shell.is-bound,
.tcm-block-shell.is-bound .tcm-map-wrap {
  max-width: 100%;
  box-sizing: border-box;
}

/* Even when the host theme marks the block alignfull, stay inside the box. */
.tcm-block-shell.is-bound {
  width: 100% !important;
  margin-inline-start: 0 !important;
  margin-inline-end: 0 !important;
}

/* Editor preview shell */
.tcm-block-ssr {
  position: relative;
  min-height: 120px;
}

/* ── Marker & Cluster Styles ─────────────────────────────────────────────────── */
.tcm-cluster-icon { background: transparent !important; border: none !important; }
.tcm-cluster-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: var(--tcm-blue);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  box-shadow: 0 2px 8px rgba(37,99,235,.4);
}

/* ─────────────────────────────────────────────────────────────────────────────
   Marker chrome resets.

   IMPORTANT: these rules only ever strip *decoration* (background, border,
   shadow) from our own div-icon wrappers. They must never set width/height on
   a Leaflet marker, because Leaflet writes the correct pixel dimensions inline
   from each icon's iconSize. A blanket `.leaflet-marker-icon svg { width:32px }`
   previously overrode the real pin geometry and collapsed single-point markers
   into white slivers with an unclickable hit box.
   ───────────────────────────────────────────────────────────────────────────── */
.tcm-map-wrap .tcm-custom-div-icon,
.tcm-map-wrap .tcm-default-marker,
.tcm-map-wrap .tcm-marker-wrap {
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  padding: 0 !important;
  margin: 0 !important;
  outline: none !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
}

/* ─────────────────────────────────────────────────────────────────────────────
   DEFAULT LOCATION DOT — the squashed-white-ellipse fix.

   This rule previously declared only border-radius, border and box-shadow,
   with NO width and NO height. The parent .tcm-marker-wrap is
   `display:flex; align-items:center; justify-content:center` at 14x14, so an
   empty <div> with no intrinsic size collapsed on both axes:

     justify-content:center  ->  width  shrinks to content = 0
     align-items:center      ->  height shrinks to content = 0

   All that remained painting was the 2px solid #fff border with a 50% radius,
   and the inline background-colour sat on a zero-area box where it could never
   be seen. Depending on how a browser resolved the cross-axis, the result was
   a thin white sliver or a squashed white ellipse.

   Explicit dimensions plus aspect-ratio and flex-shrink:0 make the dot
   incapable of collapsing, whatever the surrounding theme does.
   ───────────────────────────────────────────────────────────────────────────── */
.tcm-map-wrap .tcm-marker-wrap .tcm-marker-dot,
.tcm-marker-wrap .tcm-marker-dot,
.tcm-marker-dot {
  display: block !important;
  box-sizing: border-box !important;
  width: 14px !important;
  height: 14px !important;
  min-width: 14px !important;
  min-height: 14px !important;
  max-width: 14px !important;
  max-height: 14px !important;
  aspect-ratio: 1 / 1 !important;
  flex: 0 0 14px !important;
  border-radius: 50% !important;
  border: 2px solid #fff !important;
  box-shadow: 0 1px 4px rgba(0,0,0,.35) !important;
  opacity: 1 !important;
  visibility: visible !important;
  padding: 0 !important;
  margin: 0 !important;
  transform: none !important;
  clip-path: none !important;
  -webkit-clip-path: none !important;
  mask: none !important;
  -webkit-mask: none !important;
  background-clip: padding-box !important;
}

/* The wrapper must not shrink below the icon size either. */
.tcm-map-wrap .tcm-marker-wrap {
  width: 14px !important;
  height: 14px !important;
  box-sizing: content-box !important;
}

/* Sizing is scoped strictly to our SVG div-icons (both classes required). */
.tcm-map-wrap .tcm-custom-div-icon.tcm-svg-marker > svg {
  width: var(--tcm-icon-size, 32px) !important;
  height: var(--tcm-icon-size, 32px) !important;
  display: block !important;
  filter: drop-shadow(0px 2px 4px rgba(0,0,0,0.3));
  border-radius: 0 !important;
  clip-path: none !important;
  -webkit-clip-path: none !important;
  mask: none !important;
  -webkit-mask: none !important;
  object-fit: contain !important;
}

/* Native Leaflet raster pins: restore only, never restrict.
   No background / size / object-fit here — any of those can blank the sprite
   while the hit box survives, producing a clickable but invisible marker. */
.tcm-map-wrap .leaflet-marker-icon:not(.tcm-custom-div-icon):not(.tcm-marker-wrap):not(.tcm-default-marker),
.tcm-map-wrap img.leaflet-marker-icon,
.tcm-map-wrap img.leaflet-marker-shadow {
  opacity: 1 !important;
  visibility: visible !important;
  display: block !important;
  filter: none !important;
  clip-path: none !important;
  -webkit-clip-path: none !important;
  mask: none !important;
  -webkit-mask: none !important;
  max-width: none !important;
  max-height: none !important;
  min-width: 0 !important;
  min-height: 0 !important;
  pointer-events: auto !important;
}

/* ── Popup / Infowindow ──────────────────────────────────────────────────────── */
.tcm-popup { font-family: var(--tcm-font); }
.tcm-popup__image-wrap { position: relative; }
.tcm-popup__image-wrap img {
  width: 100%; height: 130px;
  object-fit: cover;
  border-radius: 8px 8px 0 0;
  display: block;
}
.tcm-popup__body { padding: 12px 14px; }
.tcm-popup__title { font-size: 15px; font-weight: 700; color: #0f172a; margin: 0 0 4px; }
.tcm-popup__address { font-size: 12px; color: #64748b; margin: 0 0 6px; }
.tcm-popup__teaser  { font-size: 13px; color: #475569; margin: 0 0 10px; line-height: 1.45; }
.tcm-popup__btn {
  display: inline-block;
  padding: 7px 14px;
  background: var(--tcm-blue);
  color: #fff !important;
  border-radius: 6px;
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
  transition: background var(--tcm-transition);
}
.tcm-popup__btn:hover { background: var(--tcm-blue-dark); }

.leaflet-popup-content { margin: 0 !important; }
.leaflet-popup-content-wrapper { padding: 0 !important; border-radius: 10px !important; overflow: hidden; }

/* Difficulty badge */
.tcm-diff-badge {
  position: absolute;
  top: 8px; right: 8px;
  padding: 2px 8px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 700;
  color: #fff;
  text-transform: capitalize;
}
.tcm-diff-badge--easy     { background: var(--tcm-green); }
.tcm-diff-badge--moderate { background: var(--tcm-amber); }
.tcm-diff-badge--hard     { background: var(--tcm-red);   }

/* The bottom sheet is gone. Any resurrected markup — from a cached
   stylesheet, a child theme, or a stale template — must not paint a handle
   bar below the map, which is what produced the grey hairline above the
   offline button. */
.tcm-bottom-sheet,
.tcm-bottom-sheet__handle,
.tcm-bottom-sheet__content {
  display: none !important;
}

/* ── Filter Strip ────────────────────────────────────────────────────────────── */
.tcm-filter-strip {
  position: absolute;
  top: 12px; left: 12px;
  z-index: 800;
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
}

.tcm-filter-btn {
  padding: 6px 14px;
  border-radius: 20px;
  border: 1.5px solid #1e293b !important;
  background: #ffffff !important;
  color: #1e293b !important;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,.1);
  transition: all var(--tcm-transition);
  backdrop-filter: blur(8px);
  white-space: nowrap;
}
.tcm-filter-btn:hover,
.tcm-filter-btn:focus,
.tcm-filter-btn--active {
  background: #1e293b !important;
  color: #ffffff !important;
}

/* ── Search Box ──────────────────────────────────────────────────────────────── */
.tcm-search-box {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 800;
  display: flex;
  align-items: center;
  background: var(--tcm-surface);
  border-radius: 24px;
  box-shadow: var(--tcm-shadow);
  padding: 0 14px;
  backdrop-filter: blur(10px);
  max-width: 320px;
  width: calc(100% - 140px);
}
.tcm-search-box input {
  border: none;
  background: transparent;
  outline: none;
  font-size: 14px;
  padding: 9px 0;
  color: #1e293b;
  width: 100%;
  font-family: var(--tcm-font);
}
.tcm-search-box input::placeholder { color: #94a3b8; }

/* ── Buttons (frontend shared) ───────────────────────────────────────────────── */
.tcm-btn-front {
  padding: 9px 20px;
  border-radius: 8px;
  border: 1.5px solid #1e293b !important;
  background: #ffffff !important;
  color: #1e293b !important;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: all var(--tcm-transition);
  font-family: var(--tcm-font);
}
.tcm-btn-front:hover,
.tcm-btn-front:focus {
  background: #1e293b !important;
  color: #ffffff !important;
}
.tcm-btn-front--primary {
  background: #1e293b !important;
  color: #ffffff !important;
}
.tcm-btn-front--primary:hover { 
  background: #334155 !important;
}

/* ── Geometry popup ──────────────────────────────────────────────────────────── */
.tcm-geom-popup { padding: 8px 12px; font-family: var(--tcm-font); font-size: 13px; }

/* ── Toast ───────────────────────────────────────────────────────────────────── */
.tcm-toast-notice {
  position: fixed;
  bottom: 20px;
  right: 20px;
  background: #1e293b;
  color: #fff;
  padding: 12px 24px;
  border-radius: 6px;
  z-index: 999999;
  font-family: var(--tcm-font);
  font-size: 14px;
  box-shadow: 0 4px 12px rgba(0,0,0,.25);
  pointer-events: none;
}

/* ── Responsive ──────────────────────────────────────────────────────────────── */
@media (max-width: 640px) {
  .tcm-layer-panel {
    top: auto; bottom: 0; left: 0; right: 0;
    max-width: 100%; width: 100%;
    border-radius: 12px 12px 0 0;
  }
  .tcm-layer-panel__body { max-height: 260px; }
  .tcm-style-switcher { bottom: 60px; }
  .tcm-search-box { width: calc(100% - 24px); max-width: none; }
}

/* ─────────────────────────────────────────────────────────────────────────────
   LOCATE CONTROL + USER POSITION DOT
   Nothing here runs until the visitor taps the crosshair — see
   addGeolocateControl() for why the API is never called on page load.
   ───────────────────────────────────────────────────────────────────────────── */
.tcm-locate .tcm-locate__btn {
  display: flex !important;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  color: #334155;
  background: #fff;
  cursor: pointer;
  transition: color .15s ease, background-color .15s ease;
}
.tcm-locate .tcm-locate__btn:hover { color: #2563eb; }

/* Tracking: the crosshair adopts the same blue as the dot it is showing. */
.tcm-locate .tcm-locate__btn.is-active { color: #2563eb; background: #eff6ff; }

/* Waiting on the first fix. */
.tcm-locate .tcm-locate__btn.is-busy svg { animation: tcm-locate-spin 1.1s linear infinite; }
@keyframes tcm-locate-spin { to { transform: rotate(360deg); } }

/* A real failure — not a declined permission, which is a choice, not an error. */
.tcm-locate .tcm-locate__btn.is-error { color: #dc2626; background: #fef2f2; }

.tcm-userdot {
  background: none !important;
  border: 0 !important;
  position: relative;
}
.tcm-userdot__core {
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: #2563eb;
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
}
/* The pulse is a separate element so it can scale without moving the dot. */
.tcm-userdot__pulse {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: rgba(37, 99, 235, .35);
  animation: tcm-userdot-pulse 2s ease-out infinite;
}
@keyframes tcm-userdot-pulse {
  0%   { transform: scale(.6); opacity: .8; }
  70%  { transform: scale(2.4); opacity: 0; }
  100% { transform: scale(2.4); opacity: 0; }
}

/* Respect a visitor who has asked the OS to stop animating things. */
@media (prefers-reduced-motion: reduce) {
  .tcm-userdot__pulse { animation: none; opacity: .35; transform: scale(1.6); }
  .tcm-locate .tcm-locate__btn.is-busy svg { animation: none; opacity: .6; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   TAP-HIGHLIGHT PURGE — unconditional.
   ───────────────────────────────────────────────────────────────────────────
   The existing suppression lives inside @media (hover: none), (pointer: coarse).
   That media query is the wrong gate: a touchscreen laptop and a Windows tablet
   both report hover:hover / pointer:fine while still delivering real touch
   events, so they fell outside the block and kept painting the translucent blue
   box on every tap of a marker, a control or the layers panel.

   The property only has meaning for touch input, so applying it unconditionally
   costs nothing on a mouse-only device and closes the gap on hybrids.
   ═══════════════════════════════════════════════════════════════════════════ */
.tcm-map-wrapper,
.tcm-map-wrapper *,
.tcm-map-container,
.tcm-map-container *,
.tcm-layers-panel,
.tcm-layers-panel *,
.tcm-offline-btn,
.tcm-offline-footer button,
.tcm-offline-bar button,
.leaflet-container,
.leaflet-container * {
  -webkit-tap-highlight-color: transparent !important;
}

/* Selecting the map chrome is never useful and a long-press drag on a control
   otherwise starts a text selection instead of panning. Popup body text stays
   selectable, since visitors do copy addresses out of it. */
.tcm-map-wrapper .leaflet-control-container,
.tcm-map-wrapper .leaflet-marker-icon,
.tcm-layers-panel {
  -webkit-user-select: none;
  user-select: none;
}

/* ═══════════════════════════════════════════════════════════════════════════
   CLUSTERED GEOMETRY — FADE, DON'T BLINK
   ───────────────────────────────────────────────────────────────────────────
   Point markers slide into their cluster because MarkerCluster animates their
   position. A polyline, polygon or circle cannot be animated that way — it has
   no single position to travel from — so it was simply switched to opacity 0
   and disappeared between two frames while the pins beside it glided away.

   Transitioning the opacity properties themselves closes that gap: the shape
   dissolves over the same interval the pins take to travel, so the two read as
   one motion rather than an animation plus a glitch.

   `opacity` covers the stroke on all three geometry types; `fill-opacity`
   covers the interior of polygons and circles. Both are real SVG presentation
   attributes and both are animatable, which is why this works on a vector
   layer where a plain `transition: opacity` on the element would not.

   The class is applied in tcm-map.js through the Path CONSTRUCTOR options —
   see the note there on why setStyle() cannot deliver it.
   ═══════════════════════════════════════════════════════════════════════════ */
.tcm-animated-vector-path {
  transition: opacity 0.35s ease-in-out,
              fill-opacity 0.35s ease-in-out !important;
}

/* The vertex circles and direction chevrons that decorate a route are separate
   layers, so they need the same treatment or the line would fade while its
   decorations popped out. */
.tcm-map-wrapper .leaflet-overlay-pane path.tcm-animated-vector-path,
.tcm-route-vertex,
.tcm-route-arrow {
  transition: opacity 0.35s ease-in-out,
              fill-opacity 0.35s ease-in-out !important;
}

/* A visitor who asked for less motion gets the old instant switch rather than
   a half-second of movement they did not want. */
@media (prefers-reduced-motion: reduce) {
  .tcm-animated-vector-path,
  .tcm-route-vertex,
  .tcm-route-arrow {
    transition: none !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ELEVATION PROFILE
   ───────────────────────────────────────────────────────────────────────────
   Sits between the map and the offline bar in NORMAL FLOW. Opening it pushes
   the article down rather than covering the route the visitor just clicked —
   an overlay would hide the very thing the chart is describing.
   ═══════════════════════════════════════════════════════════════════════════ */
.tcm-elevation {
  margin-block-start: 12px;
  padding: 12px 14px;
  background: var(--tcm-ele-bg, #fff);
  color: var(--tcm-ele-fg, #334155);
  border: var(--tcm-ele-border-w, 1px) solid var(--tcm-ele-bdr, #e2e8f0);
  border-radius: var(--tcm-ele-radius, 12px);
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);

  /* `hidden` is a presentation hint browsers apply with display:none, but any
     `display` rule from a theme beats it. Enforcing it keeps a closed panel
     from reserving space. */
  }
.tcm-elevation[hidden] { display: none !important; }

.tcm-ele__head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-block-end: 6px;
}

.tcm-ele__title { font-weight: 600; font-size: 14px; flex: 1 1 auto; min-width: 0; }

.tcm-ele__stats {
  display: flex;
  gap: 12px;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  opacity: .85;
}

.tcm-ele__close {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  padding: 0;
  cursor: pointer;
  font: inherit;
  line-height: 1;
  color: #64748b;
  background: #f8fafc;
  border: 1px solid #cbd5e1;
  border-radius: 8px;
  -webkit-tap-highlight-color: transparent;
}
.tcm-ele__close:hover { background: #fef2f2; border-color: #fca5a5; color: #b91c1c; }

/* The readout keeps its line whether or not it holds a value, so the chart
   below does not jump up and down as the pointer enters and leaves. */
.tcm-ele__readout {
  min-height: 1.2em;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.tcm-ele__svg {
  display: block;
  width: 100%;
  height: var(--tcm-ele-h, 180px);
  touch-action: pan-y;      /* dragging across the chart must still scroll the page */
  cursor: crosshair;
}

/* The plot is the positioning context for the axis labels, which sit OUTSIDE
   the SVG — see _markup() for why text inside a non-uniformly scaled viewBox
   renders stretched and clipped. */
.tcm-ele__plot { position: relative; }

.tcm-ele__tick {
  position: absolute;
  inset-inline-start: 0;
  font-size: 11px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: currentColor;
  opacity: .6;
  pointer-events: none;
  /* Sits over the chart's own left padding rather than stealing width. */
  padding-inline-end: 4px;
}

.tcm-ele__tick--max { top: 2px; }
.tcm-ele__tick--min { bottom: 22px; }

/* Room for the labels, matching PAD.left in the script. */
.tcm-ele__plot .tcm-ele__svg { padding-inline-start: 0; }

/* ─────────────────────────────────────────────────────────────────────────────
   THE INDICATOR THAT RIDES ALONG THE ROUTE

   Built to the same recipe as the user-position dot and the location pins: a
   solid fill in the route's own colour, a white ring, and a soft drop shadow.
   Before this it was a bare square of colour that read as a rendering glitch
   dropped on top of the map rather than as part of it — the white ring is what
   separates a marker from the tiles underneath at every zoom, on street and on
   satellite alike.
   ───────────────────────────────────────────────────────────────────────────── */
.tcm-ele-indicator { pointer-events: none; }

.tcm-ele-indicator span {
  display: block;
  width: 100%;
  height: 100%;
  border: 2px solid #fff;

  /*
   * Two rings, not one. The inner white border holds the shape against dark
   * terrain; the translucent outer ring holds it against a WHITE snowfield or
   * a bright limestone wadi, where a plain white border disappears entirely.
   */
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .45), 0 2px 6px rgba(15, 23, 42, .4);

  /* Appears with the pointer rather than blinking into existence. */
  animation: tcm-ele-pop .18s ease-out;
}

@keyframes tcm-ele-pop {
  from { transform: scale(.55); opacity: 0; }
  to   { transform: scale(1);   opacity: 1; }
}

.tcm-ele-indicator--circle  span { border-radius: 50%; }
.tcm-ele-indicator--square  span { border-radius: 2px; }

/*
 * The rotated shapes opt out of the pop, because the keyframe's transform
 * would overwrite their rotation for the length of the animation and snap
 * them upright mid-flight.
 */
.tcm-ele-indicator--diamond span {
  border-radius: 2px;
  transform: rotate(45deg);
  animation: none;
}
.tcm-ele-indicator--pin span {
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  animation: none;
}

/* ── Travel-mode glyphs ─────────────────────────────────────────────────────── */
/*
 * A hiker, a cyclist, a car, a boat. The badge is always a circle regardless
 * of the "shape" name, because a glyph inside a diamond or a teardrop is
 * unreadable at the sizes this thing is drawn at.
 */
.tcm-ele-indicator--glyph .tcm-ele-indicator__badge {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: #fff;                     /* the SVG strokes inherit this */
}

.tcm-ele-indicator--glyph .tcm-ele-indicator__badge svg {
  display: block;
  width: 62%;
  height: 62%;
}

/* A glyph is a shape in its own right; the rotations must not reach it. */
.tcm-ele-indicator--glyph span { transform: none !important; }

@media (prefers-reduced-motion: reduce) {
  .tcm-ele-indicator span { animation: none; }
}

/* ─────────────────────────────────────────────────────────────────────────────
   MAP SEARCH — the magnifier above the locate crosshair

   Collapsed it is a circle the size of the controls beneath it; open, it grows
   into a field. One element that changes width, rather than a button that
   swaps for a box: swapping would reflow the whole top-left control stack and
   make the crosshair jump down the screen as the visitor starts typing.

   It searches this map's own locations and never calls a geocoder — see the
   header of tcm-search.js for why that is a product decision and not a
   limitation.
   ───────────────────────────────────────────────────────────────────────────── */
.tcm-msearch {
  position: relative;
  display: flex;
  align-items: center;
  width: 34px;
  height: 34px;
  background: #fff;
  border-radius: 999px;
  box-shadow: 0 1px 5px rgba(0, 0, 0, .4);   /* matches .leaflet-bar exactly */
  font-family: var(--tcm-font);

  /*
   * Only the width animates. Animating the whole box would drag the shadow
   * and the border-radius through intermediate values and make the circle
   * look like it is deflating.
   */
  transition: width .22s ease;
}

.tcm-msearch.is-open { width: 252px; }

.tcm-msearch__btn {
  flex: 0 0 34px;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: 50%;
  color: #334155;
  cursor: pointer;
  transition: color .15s ease;
}

.tcm-msearch__btn:hover { color: #2563eb; }
.tcm-msearch.is-open .tcm-msearch__btn { color: #2563eb; }

/*
 * visibility, not display. A display:none field cannot be focused, and the
 * focus call fires in the same frame the class is added — so the caret would
 * land nowhere and the first keystrokes would be swallowed.
 */
.tcm-msearch__field {
  display: flex;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity .16s ease .06s;
}

.tcm-msearch.is-open .tcm-msearch__field {
  opacity: 1;
  visibility: visible;
}

.tcm-msearch__input {
  flex: 1 1 auto;
  min-width: 0;
  height: 34px;
  margin: 0;
  padding: 0;
  padding-inline-end: 4px;
  border: 0;
  background: transparent;
  outline: none;
  box-shadow: none;
  font: inherit;
  font-size: 14px;
  color: #1e293b;
}

.tcm-msearch__input::placeholder { color: #94a3b8; }

/* Chrome and Safari draw their own clear "x" on a search field; ours is drawn
   below, and two of them side by side reads as a bug. */
.tcm-msearch__input::-webkit-search-cancel-button { display: none; }

.tcm-msearch__clear {
  flex: 0 0 26px;
  width: 26px;
  height: 26px;
  display: none;
  align-items: center;
  justify-content: center;
  margin-inline-end: 5px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #f1f5f9;
  color: #64748b;
  cursor: pointer;
}

.tcm-msearch__clear:hover { background: #e2e8f0; color: #1e293b; }

/* Only offered once there is something to clear. */
.tcm-msearch.is-open.has-text .tcm-msearch__clear { display: flex; }

/* ── The results dropdown ───────────────────────────────────────────────────── */
.tcm-msearch__list {
  position: absolute;
  top: calc(100% + 6px);
  inset-inline-start: 0;
  z-index: 1000;
  width: 252px;
  max-height: 264px;
  overflow-y: auto;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 8px 26px rgba(15, 23, 42, .18);
  -webkit-overflow-scrolling: touch;
}

.tcm-msearch__list[hidden] { display: none; }

.tcm-msearch__hit {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  line-height: 1.35;
}

.tcm-msearch__hit:hover,
.tcm-msearch__hit.is-active { background: #eff6ff; }

/* The layer's own colour, so a result is recognisable before it is read. */
.tcm-msearch__dot {
  flex: 0 0 9px;
  width: 9px;
  height: 9px;
  margin-block-start: 5px;
  border-radius: 50%;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .9);
}

.tcm-msearch__text {
  display: block;
  min-width: 0;
  flex: 1 1 auto;
}

.tcm-msearch__name {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
  color: #1e293b;

  /* One line. A long trail name must not push the next result off-screen. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tcm-msearch__name mark {
  background: #fde68a;
  color: inherit;
  padding: 0;
  border-radius: 2px;
}

.tcm-msearch__sub {
  display: block;
  font-size: 11.5px;
  color: #64748b;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Says out loud that a result is currently filtered off the map, so flying to
   an empty patch of terrain is explained rather than mysterious. */
.tcm-msearch__flag {
  display: inline-block;
  margin-block-start: 3px;
  padding: 1px 6px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #64748b;
  font-size: 10.5px;
}

.tcm-msearch__empty {
  padding: 12px 10px;
  color: #64748b;
  font-size: 12.5px;
  text-align: center;
}

/* ── Public places, alongside our own locations ──────────────────────────────────── */
/*
 * The neutral pin marks a place that is NOT one of ours, and it is also what
 * OUR rows use when the map is set to present both sources identically. The
 * two treatments are deliberately the only difference between the row types:
 * a heading saying "on this map" is exactly the label a map owner may not
 * want, and a single ranked list is what every search box already looks like.
 */
.tcm-msearch__pin {
  flex: 0 0 16px;
  width: 16px;
  height: 16px;
  margin-block-start: 1px;
  color: #94a3b8;
}

.tcm-msearch__pin svg { display: block; width: 100%; height: 100%; }

.tcm-msearch__hit.is-active .tcm-msearch__pin,
.tcm-msearch__hit:hover .tcm-msearch__pin { color: #2563eb; }

/* ── Waiting on the geocoder ────────────────────────────────────────────────── */
/*
 * The spinner lives INSIDE the field rather than replacing the result list.
 * Local matches are already on screen by the time it appears, and blanking
 * them to show a loading state would take away the answer the visitor most
 * likely wanted in order to wait for one they probably do not.
 */
.tcm-msearch__spin {
  flex: 0 0 0;
  width: 0;
  height: 14px;
  margin-inline-end: 0;
  border: 2px solid #cbd5e1;
  border-top-color: #2563eb;
  border-radius: 50%;
  opacity: 0;
  transition: opacity .15s ease;
}

.tcm-msearch.is-loading .tcm-msearch__spin {
  flex: 0 0 14px;
  width: 14px;
  margin-inline-end: 6px;
  opacity: 1;
  animation: tcm-msearch-spin .8s linear infinite;
}

@keyframes tcm-msearch-spin { to { transform: rotate(360deg); } }

/* A quiet line under the results: "still looking", or "offline, saved only". */
.tcm-msearch__note {
  padding: 7px 10px;
  color: #94a3b8;
  font-size: 11.5px;
  text-align: center;
}

.tcm-msearch__note--busy { color: #64748b; }

/* ── The transient pin dropped on a chosen public place ─────────────────────────── */
/*
 * A public place has no marker of its own, so flying to one would otherwise
 * show empty terrain and read as a broken result. This pin belongs to the
 * search, not to the map's data: it carries no popup, no link and no article,
 * and it is replaced or removed the moment another result is chosen.
 */
.tcm-msearch-pin {
  background: none !important;
  border: 0 !important;
  color: #0f766e;
  filter: drop-shadow(0 3px 5px rgba(15, 23, 42, .4));
  animation: tcm-msearch-drop .28s cubic-bezier(.2, .9, .3, 1.4);

  /*
   * CLICKABLE, unlike the first version.
   *
   * It was pointer-events:none on the reasoning that a place with no article
   * behind it should not look like one of ours. The pin still reads as
   * different — its own colour, no article link inside — but a visitor who has
   * just told us which area they care about should not be met with a marker
   * that answers nothing. It opens a card offering somewhere to go next.
   */
  cursor: pointer;
}

.tcm-msearch-pin svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: currentColor;
  stroke: #fff;
  stroke-width: 1.6;
}

.tcm-msearch-pin svg circle { fill: #fff; stroke: none; }

@keyframes tcm-msearch-drop {
  from { transform: translateY(-10px); opacity: 0; }
  to   { transform: translateY(0);     opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .tcm-msearch-pin { animation: none; }
  .tcm-msearch.is-loading .tcm-msearch__spin { animation: none; opacity: .6; }
}

@media (max-width: 640px) {
  /* Wider than the desktop box: a phone has less room for the word, not more,
     and the dropdown is the whole interface once it is open. */
  .tcm-msearch.is-open { width: min(74vw, 280px); }
  .tcm-msearch__list   { width: min(74vw, 280px); }
}

@media (prefers-reduced-motion: reduce) {
  .tcm-msearch,
  .tcm-msearch__field { transition: none; }
}

/* ── The popup link that reveals the panel ────────────────────────────────── */
.tcm-popup__elevation {
  display: block;
  width: 100%;
  margin-block-start: 8px;
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  color: #1d4ed8;
  background: #eff6ff;
  border: 1px solid #93c5fd;
  border-radius: 8px;
  -webkit-tap-highlight-color: transparent;
}
.tcm-popup__elevation:hover { background: #dbeafe; }

@media (prefers-reduced-motion: reduce) {
  .tcm-elevation { scroll-behavior: auto; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   QUICK FILTER CHIPS
   ───────────────────────────────────────────────────────────────────────────
   A single minimal row above the map. The first four chips are inline; the
   rest stay collapsed behind "More filters" so a map with a dozen layers does
   not push the map itself off the screen with three rows of buttons.
   ═══════════════════════════════════════════════════════════════════════════ */
.tcm-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-block-end: 10px;
}

.tcm-chip {
  flex: 0 0 auto;
  padding: 7px 14px;
  font: inherit;
  font-size: 13px;
  line-height: 1.2;
  cursor: pointer;
  color: #334155;
  background: #fff;
  border: 1px solid #cbd5e1;
  border-radius: 999px;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
  -webkit-tap-highlight-color: transparent;
}

.tcm-chip:hover { border-color: #94a3b8; }

.tcm-chip.is-active {
  background: var(--tcm-blue, #2563eb);
  border-color: var(--tcm-blue, #2563eb);
  color: #fff;
  font-weight: 600;
}

/* Overflow chips are hidden until the bar is expanded. `display: none` rather
   than opacity: a chip that is invisible but still focusable would put the
   keyboard in a control the visitor cannot see. */
.tcm-chip--overflow { display: none; }
.tcm-chips.is-expanded .tcm-chip--overflow { display: inline-block; }

.tcm-chip--more {
  border-style: dashed;
  color: #475569;
}
.tcm-chips.is-expanded .tcm-chip--more {
  background: #f1f5f9;
  border-style: solid;
}

/* On a phone the bar scrolls sideways rather than wrapping to three rows —
   vertical space above the map is the scarcest thing on the screen. */
@media (max-width: 600px) {
  .tcm-chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .tcm-chips::-webkit-scrollbar { display: none; }
  .tcm-chips.is-expanded { flex-wrap: wrap; overflow-x: visible; }
}

/* ── Admin: chip management rows ──────────────────────────────────────────── */
.tcm-chip-rows { margin: 0; padding: 0; list-style: none; }

.tcm-chip-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  margin-block-end: 6px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  border-radius: 8px;
}

.tcm-chip-row__label { flex: 1 1 auto; min-width: 0; }
.tcm-chip-row__kind {
  flex: 0 0 auto;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: #64748b;
}
.tcm-chip-row__tools { flex: 0 0 auto; display: inline-flex; gap: 4px; }
.tcm-chip-row__tools .tcm-chip-del { color: #b91c1c; }

/* ═══════════════════════════════════════════════════════════════════════════
   OFFLINE BUTTON — THE BLUE THAT SURVIVES THE RESET
   ───────────────────────────────────────────────────────────────────────────
   Reported: after the save completes and the button returns to its default
   look, it stays blue until something else on the page is tapped.

   "Until something else is tapped" is the signature of FOCUS, and the button
   keeps focus from the tap that started the save. The base rule already pins
   `background: transparent !important`, so the blue is not a background at
   all — it is the focus ring the browser (and the theme's own button styles)
   paint as an outline or box-shadow.

   The existing resets for this live inside @media (hover: none), (pointer:
   coarse). That is the wrong gate, and the same one that hid the tap-highlight
   fix earlier: a tablet, a touchscreen laptop, and a phone in desktop mode all
   report pointer: fine and never matched it.

   Unconditional here. Keyboard users keep a ring through :focus-visible
   below — that rule is stated after this one so it wins for them alone.
   ═══════════════════════════════════════════════════════════════════════════ */
.tcm-offline-btn:focus,
.tcm-offline-btn:focus-within,
.tcm-offline-btn:active,
.tcm-offline-footer button:focus,
.tcm-offline-footer button:focus-within,
.tcm-offline-footer button:active,
.tcm-offline-bar button:focus,
.tcm-offline-bar button:focus-within,
.tcm-offline-bar button:active {
  outline: none !important;
  outline-offset: 0 !important;
  box-shadow: none !important;
  -webkit-focus-ring-color: transparent !important;
  -webkit-tap-highlight-color: transparent !important;
}

/* A pointer tap must not leave a lasting mark; a keyboard user must still be
   able to see where they are. :focus-visible fires only for the keyboard, and
   coming last it beats the blanket reset above for that case alone. */
.tcm-offline-btn:focus-visible {
  outline: 2px solid var(--tcm-blue, #2563eb) !important;
  outline-offset: 2px !important;
}

/* The success state owns the button while it is showing, so nothing inherited
   can repaint it mid-confirmation. */
.tcm-offline-btn.is-saved,
.tcm-offline-btn.is-saved:focus,
.tcm-offline-btn.is-saved:active {
  background: #22c55e !important;
  color: #fff !important;
  border-color: #22c55e !important;
}

/* Admin: the inherited-tag list on the location form. */
.tcm-tag-list { margin: 6px 0 12px; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 6px 14px; }
.tcm-tag-list__item { flex: 0 0 auto; }

/* ── The overflow toggle keeps ONE look in both states ────────────────────── */
/* It was picking up the active-chip styling when open — solid border, blue
   fill — so the control that closes the list looked like a selected filter.
   It is not a filter; it should read identically whichever way it points. */
.tcm-chips .tcm-chip--more,
.tcm-chips.is-expanded .tcm-chip--more,
.tcm-chips .tcm-chip--more.is-active,
.tcm-chips .tcm-chip--more[aria-pressed="true"] {
  background: #fff !important;
  border: 1px dashed #cbd5e1 !important;
  color: #475569 !important;
  font-weight: 400 !important;
}
.tcm-chips .tcm-chip--more:hover { border-color: #94a3b8 !important; }

/* ── Share button — modern pill, matching the chips ───────────────────────── */
.tcm-popup__share {
  gap: 6px;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 999px;
  color: var(--tcm-share-fg, #1d4ed8);
  background: var(--tcm-share-bg, #eff6ff);
  border: 1px solid var(--tcm-share-bd, #bfdbfe);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
  transition: background-color .15s ease, border-color .15s ease,
              color .15s ease, transform .12s ease;
}

.tcm-popup__share:hover,
.tcm-popup__share:focus-visible {
  background: var(--tcm-share-bg-h, #dbeafe);
  border-color: var(--tcm-share-bd-h, #93c5fd);
  transform: translateY(-1px);
}

.tcm-popup__share:active { transform: translateY(0); }

/* The confirmation tick replaces the label in place; a fixed minimum keeps the
   row from reflowing as the text swaps back and forth. */
.tcm-popup__share { min-width: 92px; justify-content: center; }

.tcm-popup__share svg { width: 15px; height: 15px; flex: 0 0 auto; }

/* ═══════════════════════════════════════════════════════════════════════════
   POPUP ACTION ROW — PRIMARY + SECONDARY, ONE UNIT
   ───────────────────────────────────────────────────────────────────────────
   The article link and the share button now read as a matched pair, the way a
   shop pairs a wide "Buy" with a narrow cart icon: same height, same corner
   radius, same padding, sitting flush beside each other. Only the colours and
   the width differ, so the important one still wins the eye.

   Everything below is driven by custom properties written from the map's own
   settings, so the whole pair is editable from the Popup Template tab rather
   than by hand-editing the template markup.

   The icon-above-text stacking came from here being EMPTY: with no rule for
   the row, the button was a plain inline-block whose SVG had no intrinsic
   width, so it claimed a line of its own. Both parts are pinned explicitly now.
   ═══════════════════════════════════════════════════════════════════════════ */
.tcm-popup__actions,
.tcm-popup__actions--auto {
  display: flex !important;
  flex-direction: row !important;
  flex-wrap: nowrap !important;
  align-items: stretch;            /* equal heights without hard-coding one */
  gap: var(--tcm-act-gap, 8px);
  margin-block-start: 10px;
  width: 100%;
}

/* Shared skin. Declared once so the two can never drift apart visually. */
.tcm-popup__actions .tcm-popup__btn,
.tcm-popup__actions .tcm-popup__share,
.tcm-popup__actions--auto .tcm-popup__btn,
.tcm-popup__actions--auto .tcm-popup__share {
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
  gap: 6px;
  box-sizing: border-box;
  min-height: var(--tcm-act-h, 40px);
  padding: var(--tcm-act-pad-t, 9px) var(--tcm-act-pad-r, 14px)
           var(--tcm-act-pad-b, 9px) var(--tcm-act-pad-l, 14px);
  border-radius: var(--tcm-act-radius, 10px);
  font-size: var(--tcm-act-fs, 13px);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;

  /*
   * The SHARE button keeps one line — it is a single short word and wrapping
   * it would make the narrow half of the pair taller than the wide half. The
   * article button overrides this below, because its caption is a sentence.
   */
  white-space: nowrap;
  transition: background-color .15s ease, border-color .15s ease,
              color .15s ease, transform .12s ease;
  -webkit-tap-highlight-color: transparent;
}

/* PRIMARY — takes the remaining width, so it is unmistakably the main action. */
.tcm-popup__actions .tcm-popup__btn,
.tcm-popup__actions--auto .tcm-popup__btn {
  flex: 1 1 auto;
  min-width: 0;

  /*
   * THE CAPTION IS NEVER CUT.
   *
   * The previous attempt clipped it with an ellipsis, on the reasoning that
   * the row had to stay one line. That was the wrong trade: a button whose
   * label reads "לחצו כאן לעוד מידע על חניון ח…" has stopped being a button
   * and become a puzzle. The visitor cannot tell what they are about to open.
   *
   * The label wraps instead and the button grows to fit it. The pair still
   * matches in height because the row is `align-items: stretch` — the share
   * button grows with its partner rather than the two drifting apart.
   */
  white-space: normal;
  overflow-wrap: anywhere;
  text-align: center;
  background: var(--tcm-cta-bg, var(--tcm-blue, #2563eb)) !important;
  color: var(--tcm-cta-fg, #ffffff) !important;
  border: 1px solid var(--tcm-cta-bd, var(--tcm-cta-bg, #2563eb));
}

.tcm-popup__actions .tcm-popup__btn:hover,
.tcm-popup__actions--auto .tcm-popup__btn:hover {
  filter: brightness(.94);
}

/* SECONDARY — hugs its own content, never competes for width. */
.tcm-popup__actions .tcm-popup__share,
.tcm-popup__actions--auto .tcm-popup__share {
  flex: 0 0 auto;
  min-width: var(--tcm-share-w, auto);
  background: var(--tcm-share-bg, #eff6ff);
  color: var(--tcm-share-fg, #1d4ed8);
  border: 1px solid var(--tcm-share-bd, #bfdbfe);
}

.tcm-popup__actions .tcm-popup__share:hover { filter: brightness(.96); }

/* The glyph is a fixed box. Without this the SVG has no intrinsic size, grows
   to the full line and pushes the label onto a second row — the exact
   reported symptom. */
.tcm-popup__actions .tcm-popup__share svg,
.tcm-popup__actions--auto .tcm-popup__share svg {
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
}

/* The label may be hidden entirely for an icon-only secondary button. */
.tcm-popup__share.is-icon-only span { display: none; }
.tcm-popup__share.is-icon-only { min-width: 0; padding-inline: var(--tcm-act-pad-t, 9px); }

/* On a very narrow phone the pair wraps rather than overflowing the card. */
@media (max-width: 360px) {
  .tcm-popup__actions,
  .tcm-popup__actions--auto { flex-wrap: wrap !important; }
  .tcm-popup__actions .tcm-popup__btn { flex: 1 1 100%; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ELEVATION HEADER — THE ✕ DRIFTS ON NARROW SCREENS
   ───────────────────────────────────────────────────────────────────────────
   The header is one flex row: title, stats, close. On desktop there is room
   for all three and the ✕ lands hard against the end edge. On a phone the
   stats block wraps onto its own line and takes the ✕ with it, so the button
   ends up floating mid-row next to the numbers instead of at the corner.

   Giving the close button `order: -1` and `margin-inline-start: auto` pins it
   to the row's END regardless of what wraps, and the stats are pushed to a
   full-width line of their own below the title.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px) {
  .tcm-ele__head {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 6px 10px;
  }

  /* Title and close share the first row; the close keeps the corner. */
  .tcm-ele__title { grid-column: 1; grid-row: 1; }
  .tcm-ele__close { grid-column: 2; grid-row: 1; justify-self: end; }

  /* Stats drop to their own full-width line rather than dragging the ✕ along. */
  .tcm-ele__stats {
    grid-column: 1 / -1;
    grid-row: 2;
    flex-wrap: wrap;
  }
}

/* ───────────────────────────────────────────────────────────────────────────
   THE PUBLIC-PLACE CARD

   Shown when a visitor picks somewhere from the search that this map has no
   article about. It reuses `.tcm-popup` wholesale so it inherits the popup
   design rather than becoming a second look to keep in sync; the rules here
   are only the differences.

   Those differences are deliberate and small. It must be recognisable as a
   different KIND of answer — no article behind it — without looking like a
   downgrade, because it is the one thing standing between a dead-end search
   and another page view.
   ─────────────────────────────────────────────────────────────────────────── */
.tcm-popup-wrap--place .tcm-popup {
  --tcm-place: currentColor;
}

.tcm-popup--place .tcm-popup__title {
  /* No article means no link, so the title is a statement, not a promise. */
  margin-block-end: 4px;
}

.tcm-popup--place .tcm-popup__teaser {
  color: #475569;
  font-size: 13px;
  line-height: 1.5;
}

/*
 * The card's own button. It borrows the pair's shared geometry — the same
 * corner radius, height and padding the article button uses — so the map has
 * one button shape rather than two.
 */
.tcm-popup--place .tcm-popup__btn {
  width: 100%;
  justify-content: center;
}

.tcm-popup--place .tcm-popup__image-wrap {
  max-height: 130px;
  overflow: hidden;
}

.tcm-popup--place .tcm-popup__image {
  width: 100%;
  height: 130px;
  object-fit: cover;
  display: block;
}

/* ───────────────────────────────────────────────────────────────────────
   THE DIFFICULTY BADGE

   This had NO styling at all. tcm-popup.js emits `class="tcm-popup-diff"`;
   the stylesheet above defines `.tcm-diff-badge`. Two different strings, so
   no rule ever matched: what shipped was a bare inline <span> with nothing
   but the background colour the script writes inline, sitting inside the
   image wrapper's `overflow: hidden` rounded corner — which is why it looked
   sheared off at the top-left curve.

   The old `.tcm-diff-badge` rules are left in place: nothing emits that class
   today, but a hand-edited popup template might, and removing them would
   silently break it.
   ─────────────────────────────────────────────────────────────────────── */
/*
 * ITS OWN ROW, not an overlay.
 *
 * It was absolutely positioned over the image. That worked on a card WITH a
 * picture and fell apart without one: the image wrapper collapses to nothing,
 * so the badge landed on top of the title.
 *
 * tcm-popup.js now lifts it out into `.tcm-popup__diffrow`, between the
 * picture and the body. Picture, grade, title, text, buttons — one order that
 * holds whether there is an image or not.
 */
.tcm-popup__diffrow {
  display: flex;
  padding: 10px 14px 0;
}

.tcm-popup-diff {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 11px;
  border-radius: 999px;

  font-size: 11.5px;
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: .01em;
  color: #fff;
  white-space: nowrap;

  /*
   * A white ring and a shadow, the same treatment the map markers get. A flat
   * chip on a photograph disappears into whatever is behind it; the ring is
   * what separates it from the image at any brightness.
   */
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .9), 0 2px 6px rgba(15, 23, 42, .3);

  /* The script writes the colour inline; this is only the fallback for a
     template that emits the element without one. */
  background: #64748b;
}

/* A leading dot, so the grade is legible without relying on colour alone. */
.tcm-popup-diff::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .85);
  flex: 0 0 auto;
}

/*
 * The image is no longer a positioning context for anything, so it does not
 * need to clip. A badge left inside it by a hand-edited template still shows,
 * because nothing here hides it — it simply sits in the flow.
 */
.tcm-popup__image-wrap .tcm-popup-diff {
  margin: 10px 14px 0;
}

/* Nothing follows the picture directly any more, so the row supplies the gap
   the absolute badge used to occupy. */
.tcm-popup__diffrow + .tcm-popup__body { padding-block-start: 8px; }
