/* ==========================================================================
   TSF MAP
   Companion to js/tsf-map.js (archive), js/tsf-listing-map.js (single Listing)
   and js/tsf-map-style.js (the palette mirror).

   Two jobs: give the map a card to live in instead of floating on the page, and
   style the markers now that they are DOM rather than 15px PNG sprites.

   MARKER PINS ONLY EXIST ON THE ADVANCED PATH. Until TSF_MAPS_MAP_ID is set in
   wp-config, both maps fall back to google.maps.Marker and the .tsf-pin rules
   below simply never match anything. Nothing here breaks in the meantime.
   ========================================================================== */

/* --------------------------------------------------------------------------
   THE CARD
   Height stays wherever it is set (currently Elementor custom CSS on the map
   widget) — only the frame is claimed here, so the two can't fight.
   -------------------------------------------------------------------------- */
.tsf-map,
.tsf-map-canvas {
    border: 1px solid var(--tsf-line-soft, #2A2A2A);
    border-radius: var(--tsf-radius-md, 10px);
    overflow: hidden;
    background: var(--tsf-surface-sunken, #0C0C10);
}

/* --------------------------------------------------------------------------
   GOOGLE'S OWN CHROME
   The Map / Satellite / fullscreen controls ship white and rectangular, which
   is the single loudest thing on a dark map. Toned to the card's surfaces.
   These are Google's internal class names — they are stable in practice but not
   contractual, so everything here is cosmetic and safe to lose.
   -------------------------------------------------------------------------- */
.tsf-map .gm-style .gm-style-mtc > button,
.tsf-map .gm-style button.gm-control-active,
.tsf-map-canvas .gm-style button.gm-control-active {
    background-color: var(--tsf-surface-panel, #1A1A1A) !important;
    color: var(--tsf-text, #CBCBCB) !important;
    border-color: var(--tsf-line-strong, #333333) !important;
    box-shadow: none !important;
}

.tsf-map .gm-style .gm-style-mtc > button:hover,
.tsf-map .gm-style button.gm-control-active:hover {
    background-color: var(--tsf-surface-raised, #151515) !important;
    color: var(--tsf-text-bright, #FFFFFF) !important;
}

/* --------------------------------------------------------------------------
   MARKER PINS
   The dot itself is still the icon tsf_determine_map_icon() picks — 24 of them,
   one per haunt type, and the thing the legend documents. Converting those to
   CSS means pinning down 24 hex values first, so for now the DOM wraps them and
   supplies what a PNG never could: hover, focus and selected states.
   -------------------------------------------------------------------------- */
.tsf-pin {
    position: relative;
    width: 15px;
    height: 15px;
    display: block;
    border-radius: 50%;
    cursor: pointer;
    /* A hairline of the map's own ground, so a dot never dissolves into a road
       or a state line it happens to sit on. */
    box-shadow: 0 0 0 1.5px rgba(12, 12, 16, 0.85);
    transition: transform 140ms ease-out, box-shadow 140ms ease-out;
    will-change: transform;
}

.tsf-pin-dot {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 50%;
}

.tsf-pin:hover {
    transform: scale(1.45);
    box-shadow: 0 0 0 1.5px rgba(12, 12, 16, 0.9), 0 0 0 4px rgba(255, 0, 0, 0.35);
}

/* The selected state. js/tsf-map.js already toggles this and raises zIndex on
   click — the details pane will read the same selection rather than inventing
   its own. */
.tsf-pin.is-selected {
    transform: scale(1.6);
    box-shadow: 0 0 0 2px var(--tsf-bg, #16161A), 0 0 0 4px var(--tsf-red, #FF0000),
                0 0 14px rgba(255, 0, 0, 0.5);
}

/* --------------------------------------------------------------------------
   CLUSTER BUBBLES
   Stand in for a bucket of pins at the current zoom (see the clustering block in
   js/tsf-map.js). Deliberately NOT red: red is the selected-pin colour and the
   brand's call-to-action, and a map dotted with red circles would read as "these
   are the important ones" rather than "these are many". Neutral surface, brand
   red only on the ring, which is enough to tie it to the pins.
   -------------------------------------------------------------------------- */
.tsf-cluster {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--tsf-surface-panel, #1A1A1A);
    border: 2px solid var(--tsf-red, #FF0000);
    color: var(--tsf-text-bright, #FFFFFF);
    font-family: var(--tsf-font-body, "Roboto", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif);
    font-size: 0.78rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    cursor: pointer;
    /* Same ground-coloured hairline the pins wear, so a bubble sitting on a road
       or a state line stays legible. */
    box-shadow: 0 0 0 1.5px rgba(12, 12, 16, 0.85), 0 2px 10px rgba(0, 0, 0, 0.55);
    transition: transform 140ms ease-out;
    will-change: transform;
}

/* Size carries magnitude, so a glance reads density without reading numbers. */
.tsf-cluster--md { width: 42px; height: 42px; font-size: 0.82rem; }
.tsf-cluster--lg { width: 52px; height: 52px; font-size: 0.88rem; }

.tsf-cluster:hover { transform: scale(1.12); }

@media (prefers-reduced-motion: reduce) {
    .tsf-cluster { transition: none; }
}

/* Single-Listing map: one pin, no icon behind it, so it draws its own. */
.tsf-pin--single {
    width: 18px;
    height: 18px;
    background: var(--tsf-red, #FF0000);
    box-shadow: 0 0 0 2px var(--tsf-bg, #16161A), 0 0 16px rgba(255, 0, 0, 0.55);
}

@media (prefers-reduced-motion: reduce) {
    .tsf-pin { transition: none; }
}

/* ==========================================================================
   DETAILS PANE
   Replaces the info windows on the archive map. js/tsf-map.js builds it once
   and appends it INSIDE #map, so everything here is positioned against the map
   itself — not against whatever Elementor container the widget happens to sit
   in, which is markup this repo cannot see.

   Google's own info windows are gone entirely: no marker opens one, and
   clickableIcons is off so POI clicks cannot either. Nothing here needs to
   fight .gm-style-iw any more.
   ========================================================================== */

/* Added to #map by buildPane(). Google sets both of these on the map container
   itself, so this only guarantees them rather than changing anything. */
.tsf-map-hosts-pane {
    position: relative;
    overflow: hidden;
}

/* A floating card inside the map, NOT a full-bleed rail against its left edge.
   That is a licence constraint before it is a taste one: the Google logo sits at
   the map's bottom-left and the "Map data" attribution at its bottom-right, and
   the Maps Platform terms require both to stay visible. Neither can be moved by
   the API, so the pane insets away from them instead. The 46px subtracted from
   max-height is that 12px top inset plus a 34px floor that clears the ~29px
   attribution strip. Do not stretch this to the edges.

   It is anchored at the top and sized by its content rather than pinned top and
   bottom: one listing is five short elements, and a full-height card with 60%
   dead space in it would look like a bug. */
.tsf-map-pane {
    position: absolute;
    top: 12px;
    left: 12px;
    max-height: calc(100% - 46px);
    width: min(340px, calc(100% - 24px));
    z-index: 5;               /* above .gm-style, which is a sibling below it */

    display: flex;
    flex-direction: column;
    background: var(--tsf-surface-panel, #1A1A1A);
    border: 1px solid var(--tsf-line-soft, #2A2A2A);
    border-radius: var(--tsf-radius-md, 10px);
    box-shadow: var(--tsf-shadow-card, 0 13px 50px -13px #000000);
    color: var(--tsf-text, #CBCBCB);
    font-family: var(--tsf-font-body, "Roboto", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif);

    /* visibility (not display) so the slide can animate, and so a closed pane is
       still out of the tab order and the accessibility tree. The extra 24px on
       the transform carries the shadow off-canvas with it. */
    visibility: hidden;
    transform: translateX(calc(-100% - 24px));
    transition: transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1),
                visibility 0s linear 220ms;
}

.tsf-map-pane.is-open {
    visibility: visible;
    transform: none;
    transition: transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1), visibility 0s;
}

.tsf-map-pane:focus { outline: none; }   /* it is a container, not a control */

.tsf-map-pane__scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;   /* keep the map from panning at the scroll end */
    padding: 18px 18px 20px;
    display: flex;
    flex-direction: column;
    gap: var(--tsf-space-5, 13px);
}

/* --- Close ---------------------------------------------------------------- */
.tsf-map-pane__close {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 1;
    width: 30px;
    height: 30px;
    display: grid;
    place-items: center;
    padding: 0;
    border: 1px solid var(--tsf-line-soft, #2A2A2A);
    border-radius: var(--tsf-radius-round, 50%);
    background: var(--tsf-surface-sunken, #0C0C0C);
    color: var(--tsf-text-muted, #8A8A8A);
    cursor: pointer;
    transition: color var(--tsf-transition, 180ms ease-in-out),
                border-color var(--tsf-transition, 180ms ease-in-out);
}

.tsf-map-pane__close svg {
    width: 14px;
    height: 14px;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    fill: none;
}

.tsf-map-pane__close:hover {
    color: var(--tsf-text-bright, #FFFFFF);
    border-color: var(--ha-line-hover, #666666);
}

.tsf-map-pane__close:focus-visible {
    outline: none;
    box-shadow: var(--ha-focus-ring, 0 0 0 3px rgba(255, 0, 0, .45));
}

/* --- Head ----------------------------------------------------------------- */
.tsf-map-pane__head {
    display: flex;
    align-items: flex-start;
    gap: var(--tsf-space-4, 10px);
    padding-right: 30px;   /* clear of the close button */
}

.tsf-map-pane__logo-link { flex: 0 0 auto; display: block; }

.tsf-map-pane__logo {
    width: 64px;
    height: 64px;
    object-fit: contain;
    display: block;
    border-radius: var(--tsf-radius-sm, 8px);
    background: var(--tsf-surface, #0F0F0F);
}

.tsf-map-pane__heading {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--tsf-space-2, 6px);
    min-width: 0;
}

.tsf-map-pane__pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 9px;
    border-radius: var(--tsf-radius-xl, 31px);
    background: var(--tsf-surface-sunken, #0C0C0C);
    border: 1px solid var(--tsf-line-soft, #2A2A2A);
    font-size: var(--tsf-size-2xs, 0.75rem);
    text-transform: uppercase;
    letter-spacing: var(--tsf-tracking-wide, 0.5px);
    color: var(--tsf-text-muted, #8A8A8A);
}

.tsf-map-pane__pill-dot { display: block; border-radius: 50%; }

.tsf-map-pane__title {
    margin: 0;
    font-size: var(--tsf-size-md, 1.15rem);
    line-height: var(--tsf-leading-tight, 1.2);
    font-weight: var(--tsf-weight-strong, 600);
    /* Long haunt names are the norm here, so wrap rather than truncate. */
    overflow-wrap: anywhere;
}

/* (0,2,1) and (0,3,1) — a bare `.tsf-map-pane__title a` is (0,1,1), which merely
   TIES the kit's `a` rule and would then win or lose on enqueue order. See the
   note above the action buttons. */
.tsf-map-pane .tsf-map-pane__title a {
    color: var(--tsf-text-strong, #F2F2F2);
    text-decoration: none;
}

.tsf-map-pane .tsf-map-pane__title a:hover { color: var(--ha-link, #FF6B6B); }

.tsf-map-pane__address {
    margin: 0;
    font-size: var(--tsf-size-xs, 0.82rem);
    line-height: var(--tsf-leading-body, 1.6);
    color: var(--tsf-text-muted, #8A8A8A);
}

/* --- Actions -------------------------------------------------------------- */
.tsf-map-pane__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--tsf-space-3, 8px);
}

/* EVERY anchor rule below carries the `a` element selector AND the .tsf-map-pane
   scope, and that is not style — it is arithmetic. The Elementor kit ships
   `.elementor-kit-56038 a { color:#FF6600 }` at (0,1,1) and its `:hover` at
   (0,2,1). A bare `.tsf-map-pane__cta` is (0,1,0), so it LOSES and the button
   text renders orange on red. `.tsf-map-pane a.tsf-map-pane__cta` is (0,2,1) and
   wins outright; the `:hover` pairs reach (0,3,1) and beat the kit's hover. No
   !important needed. Same trap as the site header — check the numbers before
   adding any anchor rule here. */
.tsf-map-pane a.tsf-map-pane__cta,
.tsf-map-pane a.tsf-map-pane__ghost {
    flex: 1 1 auto;
    text-align: center;
    padding: 9px 14px;
    border-radius: var(--tsf-radius-lg, 13px);
    font-size: var(--tsf-size-xs, 0.82rem);
    font-weight: var(--tsf-weight-strong, 600);
    letter-spacing: var(--tsf-tracking-wide, 0.5px);
    text-decoration: none;
    white-space: nowrap;
    transition: background-color var(--tsf-transition, 180ms ease-in-out),
                color var(--tsf-transition, 180ms ease-in-out),
                border-color var(--tsf-transition, 180ms ease-in-out);
}

.tsf-map-pane a.tsf-map-pane__cta {
    background: var(--tsf-red-solid, #BB0000);
    border: 1px solid var(--tsf-red-solid, #BB0000);
    color: var(--tsf-text-bright, #FFFFFF);
}

.tsf-map-pane a.tsf-map-pane__cta:hover {
    background: var(--tsf-red-hover, #C00000);
    border-color: var(--tsf-red-hover, #C00000);
    color: var(--tsf-text-bright, #FFFFFF);
}

.tsf-map-pane a.tsf-map-pane__ghost {
    background: transparent;
    border: 1px solid var(--tsf-line-strong, #333333);
    color: var(--tsf-text, #CBCBCB);
}

.tsf-map-pane a.tsf-map-pane__ghost:hover {
    border-color: var(--ha-line-hover, #666666);
    color: var(--tsf-text-bright, #FFFFFF);
}

.tsf-map-pane a.tsf-map-pane__cta:focus-visible,
.tsf-map-pane a.tsf-map-pane__ghost:focus-visible,
.tsf-map-pane .tsf-map-pane__title a:focus-visible {
    outline: none;
    box-shadow: var(--ha-focus-ring, 0 0 0 3px rgba(255, 0, 0, .45));
}

/* --- The Haunt Advisor seam ----------------------------------------------
   Empty until something mounts into it, so it must cost nothing when it is.
   :empty keeps the gap from the pane's flex layout out of the way; the rule
   below is what an eventual HA block gets for free. See fillPane() in
   js/tsf-map.js for the event and the data-listing-id contract.
   -------------------------------------------------------------------------- */
.tsf-map-pane__ext {
    padding-top: var(--tsf-space-5, 13px);
    border-top: 1px solid var(--tsf-line-soft, #2A2A2A);
}

/* Wins on specificity, not order — the divider above must not show on the
   listings (currently all of them) where nothing has mounted. */
.tsf-map-pane__ext:empty { display: none; }

/* --- Narrow screens: compact panel, docked TOP ----------------------------
   A 340px panel would swallow a phone-width map, so below the breakpoint it
   spans the width instead — but it stays at the TOP and gets shorter.

   Top, not bottom, because of how a phone is actually held: pinch-zoom and
   two-finger pan happen in the lower two-thirds of the screen, under the thumbs.
   A bottom sheet sits exactly there and you end up reaching over it to work the
   map. Up top it is out of the gesture area, and it also leaves Google's zoom,
   Street View and attribution — all bottom-anchored — uncovered.

   The trade is that an open panel covers the Map/Satellite and fullscreen
   controls at this width. They come back the moment it is dismissed.

   panClearOfPane() picks its axis and direction from the pane's measured box,
   so moving the panel here cannot desync the map nudge from it.
   -------------------------------------------------------------------------- */
@media (max-width: 700px) {
    .tsf-map-pane {
        top: 10px;
        left: 10px;
        right: 10px;
        width: auto;
        max-height: min(46%, 240px);
        transform: translateY(calc(-100% - 24px));
    }

    /* Compact: this is a glance, not a page. Everything tightens a step. */
    .tsf-map-pane__scroll {
        padding: 12px 12px 14px;
        gap: var(--tsf-space-3, 8px);
    }

    .tsf-map-pane__head { gap: var(--tsf-space-3, 8px); padding-right: 26px; }

    .tsf-map-pane__logo { width: 46px; height: 46px; }

    .tsf-map-pane__title { font-size: var(--tsf-size-sm, 0.9rem); }

    .tsf-map-pane__close { top: 6px; right: 6px; width: 26px; height: 26px; }

    .tsf-map-pane a.tsf-map-pane__cta,
    .tsf-map-pane a.tsf-map-pane__ghost { padding: 7px 12px; }
}

@media (prefers-reduced-motion: reduce) {
    .tsf-map-pane,
    .tsf-map-pane.is-open { transition: visibility 0s; }
}

/* ==========================================================================
   LEGEND
   js/tsf-map.js inserts this immediately after #map and rebuilds it from the
   markers on every refresh. It replaces a PNG image widget that was gated to
   Haunted Attractions — which is why Haunted Places and Spooky Spots used to
   have no key at all.

   Styled as the BOTTOM OF THE MAP CARD, not as a thing under it: square top
   corners, rounded bottom ones, and a -1px top margin that collapses onto the
   map's own bottom border where one exists. That is the whole answer to the
   legend reading as an afterthought — it stops being a separate object.
   ========================================================================== */
.tsf-map-legend {
    margin-top: -1px;
    padding: 12px 14px 14px;
    border: 1px solid var(--tsf-line-soft, #2A2A2A);
    border-radius: 0 0 var(--tsf-radius-md, 10px) var(--tsf-radius-md, 10px);
    background: var(--tsf-surface, #0F0F0F);
    font-family: var(--tsf-font-body, "Roboto", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif);
}

/* The UA [hidden] rule is display:none at (0,0,0) and loses to almost anything
   a theme sets on `section`. Stated explicitly, the same way HA had to state it
   for its Load More button. */
.tsf-map-legend[hidden] { display: none; }

.tsf-map-legend__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--tsf-space-4, 10px);
    margin-bottom: var(--tsf-space-4, 10px);
}

/* (0,2,1): the Elementor kit styles bare `h2` at (0,1,1) with the display face
   at heading size, which would land a 32px "MARKER KEY" on top of the map. */
.tsf-map-legend h2.tsf-map-legend__title {
    margin: 0;
    padding: 0;
    font-family: inherit;
    font-size: var(--tsf-size-3xs, 0.72rem);
    font-weight: var(--tsf-weight-strong, 600);
    line-height: 1.4;
    text-transform: uppercase;
    letter-spacing: var(--tsf-tracking-caps, 0.12em);
    color: var(--tsf-text-muted, #8A8A8A);
}

.tsf-map-legend__count {
    font-size: var(--tsf-size-2xs, 0.75rem);
    color: var(--tsf-text-faint, #999999);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* (0,2,1) again — the theme's `ul` rules carry an indent and a bottom margin. */
.tsf-map-legend ul.tsf-map-legend__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--tsf-space-2, 6px) var(--tsf-space-3, 8px);
}

.tsf-map-legend__item {
    display: inline-flex;
    align-items: center;
    gap: var(--tsf-space-2, 6px);
    margin: 0;
    padding: 4px 10px 4px 7px;
    border: 1px solid var(--tsf-line-soft, #2A2A2A);
    border-radius: var(--tsf-radius-xl, 31px);
    background: var(--tsf-surface-raised, #151515);
    font-size: var(--tsf-size-2xs, 0.75rem);
    line-height: 1.3;
    color: var(--tsf-text, #CBCBCB);
}

.tsf-map-legend__dot {
    display: block;
    flex: 0 0 auto;
    border-radius: 50%;
    /* Same hairline the pins wear, so a chip reads as the pin it stands for. */
    box-shadow: 0 0 0 1.5px rgba(12, 12, 16, 0.85);
}

/* Chips wrap against each other, never inside themselves — a two-line pill with
   the count orphaned below the name is the one way this layout looks broken. */
.tsf-map-legend__label { white-space: nowrap; }

.tsf-map-legend__n {
    font-variant-numeric: tabular-nums;
    color: var(--tsf-text-muted, #8A8A8A);
}

@media (max-width: 700px) {
    .tsf-map-legend { padding: 10px 12px 12px; }

    /* A national view can key 20-odd types. On a phone that is a wall, so cap it
       and let the chips scroll inside their own box rather than pushing the
       listings grid down the page. */
    .tsf-map-legend ul.tsf-map-legend__list {
        max-height: 108px;
        overflow-y: auto;
        overscroll-behavior: contain;
    }
}
