/* Leaflet sets `font-family: "Helvetica Neue", Arial, ...` on .leaflet-container,
   so everything inside the map -- popup title, address, category pills -- rendered
   in a different face to the rest of the site. At font-weight 600 that reads as
   noticeably bolder than the identical pill on a venue card, which is Geist.

   Inheriting is the fix rather than lowering the weight: the pills use the exact
   class string from partials/category-pills.blade.php, and dropping to
   font-medium here would make them differ from the cards in the other direction
   the moment anyone compared them side by side.

   MapLibre needs the class REPEATED; Leaflet did not. maplibre-gl.css is
   injected into <head> at runtime by globe.js, so it always lands after this
   file and beat a plain `.maplibregl-map` on source order -- which is why the
   globe's popup title rendered in Arial next to a card title in Geist long
   after this rule was written. The duplicated class buys the specificity to
   win without !important. Leaflet's sheet is a normal <link> ahead of this
   one, so its selector never needed the trick; it is doubled anyway so the two
   halves of this rule cannot be read as saying different things.

   `inherit` rather than naming the face: it is set once on body from
   resources/css/components.css, and the map should follow it rather than hold
   a second copy that has to be remembered on the day it changes. This comment
   said "Hanken" until 16 Sep 2026, which is exactly the drift the rule avoids. */
.leaflet-container.leaflet-container,
.maplibregl-map.maplibregl-map,
.leaflet-popup-content,
.maplibregl-popup-content {
    font-family: inherit;
}

.leaflet-popup-content-wrapper,
.maplibregl-popup-content {
    padding: 0px;
}
.leaflet-popup-content,
.maplibregl-popup-content {
    padding: 0px;
    margin: 0px;
    /* Both, and not just width: Leaflet measures the popup from its content, so a
       child wider than this box grows the whole popup rather than being clipped. */
    width: 300px;
    max-width: 300px;
    min-height: 260px;
    box-sizing: border-box;
    overflow: hidden;
}
.leaflet-popup-content img,
.maplibregl-popup-content img {
    /* The template in public/js/listing.js marks this image up with Tailwind
       utilities (object-cover h-48 w-full), and NONE of them exist: Tailwind does
       not scan public/js, so those classes are never generated. The image was
       therefore rendering at its natural width — 1200px+ for a venue photo — with
       only the height below constraining it, which is what made the popup
       enormous.

       So the real sizing has to live here, in plain CSS. width and object-fit are
       the two that were missing. */
    display: block;
    width: 100%;
    max-width: 100%;
    height: 120px;
    object-fit: cover;
    border-top-left-radius: 8px;
    border-top-right-radius: 8px;
}
.leaflet-popup-content .content,
.maplibregl-popup-content .content {
    padding: 10px;
}
.leaflet-popup-content .categories,
.maplibregl-popup-content .categories {
    margin-top: 0px;
    margin-bottom: 5px;
    gap: 4px;
}
/* .category-tag was the popup's own pill treatment — uppercase, white on red,
   sized here because Tailwind does not scan public/js. It is gone: the popup now
   emits the same markup as partials/category-pills.blade.php, and those utility
   classes DO exist in app.css because that Blade partial puts them there. Adding
   any sizing back here would fight the shared component and reintroduce the
   difference this removed. */
/* Leaflet ships `.leaflet-container a { color:#0078A8 }` — specificity (0,2,0),
   which outranks Tailwind's single-class `.text-gray-600` (0,1,0). Every link in
   the popup therefore rendered Leaflet blue: the category pills, and the city /
   state / country links. These re-assert the same palette values at (0,3,0) so
   the popup matches the venue cards.

   Values copied from the compiled app.css rather than retyped, so they cannot
   drift from the Tailwind palette.

   EVERY LINE HERE USED TO END `},` -- a comma after the closing brace. CSS has
   no such separator between rules: the comma becomes the first token of the
   NEXT rule's selector list, which makes that list invalid, and an invalid
   selector list means the browser drops the whole rule silently. Chained down
   twelve lines it took out all but the first pill colour AND the `.title` rule
   below, so popup titles fell back to maplibre's 12px black and the pills to
   the default link colour. Nothing errors; it just renders wrong. */
.leaflet-popup-content a.text-white   { color: rgb(255 255 255); }
.maplibregl-popup-content a.text-white   { color: rgb(255 255 255); }
.leaflet-popup-content a.text-gray-600{ color: rgb(75 85 99); }
.maplibregl-popup-content a.text-gray-600{ color: rgb(75 85 99); }
.leaflet-popup-content a.text-gray-400{ color: rgb(156 163 175); }
.maplibregl-popup-content a.text-gray-400{ color: rgb(156 163 175); }
.leaflet-popup-content a.text-red     { color: rgb(255 77 85); }
.maplibregl-popup-content a.text-red     { color: rgb(255 77 85); }
/* Hover intents, same as the card pills: grey pills go red, the placement pills
   (black / gold) keep white text. */
.leaflet-popup-content a.text-gray-600:hover { color: rgb(255 77 85); }
.maplibregl-popup-content a.text-gray-600:hover { color: rgb(255 77 85); }
.leaflet-popup-content a.text-white:hover    { color: rgb(255 255 255); }
.maplibregl-popup-content a.text-white:hover    { color: rgb(255 255 255); }
/* Matches the card heading in partials/business.blade.php, which is
   `text-red text-lg capitalize` -- 18px on Tailwind's 28px line-height. The
   24px here was a hand-picked value that read tighter than every other title
   on the site as soon as a venue name wrapped to two lines. */
.leaflet-popup-content .title,
.maplibregl-popup-content .title {
    color: #ff4d55;
    font-size: 18px;
    line-height: 28px;
    text-transform: capitalize;
    margin: 0px 0px 4px 0px;
}
.leaflet-popup-content .link,
.maplibregl-popup-content .link {
    color: #ff4d55 !important;
}
.leaflet-popup-content .link:hover,
.maplibregl-popup-content .link:hover {
    color: white !important;
}
/* Matches the venue card's address block (text-xs text-grey capitalize) rather
   than the old 16px, which made the popup read as a different component to the
   cards sitting next to it on the same page. */
.leaflet-popup-content .city-state,
.maplibregl-popup-content .city-state,
.leaflet-popup-content .country,
.maplibregl-popup-content .country,
.leaflet-popup-content .address,
.maplibregl-popup-content .address {
    margin: 0px 0px 2px 0px;
    font-size: 12px;
    line-height: 16px;
    text-transform: capitalize;
    /* Deliberately no colour. The card's address block asks for `text-grey`,
       which is not a class that exists in app.css (no `grey` in the Tailwind
       palette, and none defined) -- so on the card this text inherits. Setting a
       grey here would have made the popup differ from the card in the one way
       this change was meant to remove. Fix the card's dead class first if the
       grey is actually wanted, then set it in both places. */
}
/* The place names inside stay red, as they are on the card. */
.leaflet-popup-content .city-state a,
.maplibregl-popup-content .city-state a,
.leaflet-popup-content .country a,
.maplibregl-popup-content .country a {
    text-transform: none;
}

/* Zoom control: no borders, and the two buttons separated by a gap instead.

   Leaflet draws two of them and both had to go:
     .leaflet-touch .leaflet-bar  -> border: 2px solid rgba(0,0,0,.2)   (the box)
     .leaflet-bar a               -> border-bottom: 1px solid #ccc      (the divider)
   The touch variant is the one that shows on a phone, so removing only
   `.leaflet-bar`'s border would have looked fixed on desktop and unchanged on
   the device this is for. Both selectors are listed rather than a blanket
   `border: none` on every control, which would also flatten the scale bar and
   the layers box.

   The + and - are now two separate rounded buttons with 2px between them, so
   the divider border has nothing left to divide. */
.leaflet-control-zoom.leaflet-bar.leaflet-control,
.leaflet-touch .leaflet-control-zoom.leaflet-bar.leaflet-control {
    border: none;
}
.leaflet-control-zoom-in,
.leaflet-bar a.leaflet-control-zoom-in {
    border: none;
    border-bottom: none;
    margin-bottom: 2px;
}

/* Position only. The look — circle, ink border, page fill, yellow hover — lives
   in resources/css/blocks.css beside the marker this button drops, so the
   control and its result are styled in one place. This file is loaded AFTER
   app.css, so anything cosmetic left here would silently win over the palette;
   that is how it stayed a white rounded square with a red raster inside it. */
.map-control-user-location {
    z-index: 500;
    bottom: 10px;
    left: 10px;
}

/* Below the useful card + map width, the map becomes a bottom-aligned panel.
   The shared header remains visible, and the regular results get the full row. */
.live-overview { --map-header-offset: 97px; }

@media (max-width: 1199px) {
    body.map-open { overflow: hidden; }

    .live-overview .btn-toggle-map {
        visibility: visible !important;
    }

    .live-overview .viewtab {
        display: inline-flex !important;
        align-items: center;
    }

    .live-overview .map-widen-btn {
        display: none !important;
    }

    .live-overview .map-container {
        display: none;
        position: fixed;
        z-index: 30;
        top: auto;
        right: 0;
        bottom: 0;
        left: 0;
        width: 100%;
        min-height: 0;
        height: calc(100vh - var(--map-header-offset));
        border-radius: 24px 24px 0 0;
    }

    @supports (height: 100dvh) {
        .live-overview .map-container {
            height: calc(100dvh - var(--map-header-offset));
        }
    }

    body.map-open .ad-block { visibility: hidden; }
}

@media (max-width: 960px) {
    .live-overview { --map-header-offset: 82px; }
}

/* Push Leaflet zoom/attribution controls clear of the mobile navbar/search overlay */
@media (max-width: 639px) {
    /* Level with the active-filter chips, which float at top-3 (12px). The bar
       is inset left-12/right-12 in partials/map.blade.php so it leaves this
       corner free -- the two sit side by side rather than one below the other.

       Set on the CONTROL, with the container zeroed. Leaflet already ships
       `.leaflet-top .leaflet-control { margin-top: 10px }`, so a margin on the
       container ADDS to it rather than replacing it -- two margins that sum are
       what put the +/- below the bar in the first place. One source of truth.

       resources/css/app.css also carried this selector at 40px !important,
       globally. That beat specificity and load order both, so nothing set here
       had any effect until it was scoped to >=640px. If the offset ever stops
       responding to this rule again, look there first. */
    .leaflet-top { margin-top: 12px; }
    .leaflet-top.leaflet-left .leaflet-control { margin-top: 2px; }

}

.venue-card {
    transition: opacity 0.2s ease;
}
.venue-card.reordering {
    opacity: 0.5;
}

/* The area OUTSIDE the globe. Under Leaflet the tiles filled the container, so
   the container's own background was never visible; a globe leaves the corners
   showing, and map-container carried bg-red — which rendered a bright red void
   around the planet. #eef1f5 was the first answer and REMAINS the default for
   any map that is not given a sky — the venue-detail map, which is zoomed to an
   address and never shows the void anyway. The listing map and the homepage
   globe both get the starfield instead; see the sky block at the end. */
.maplibregl-map,
.maplibregl-canvas-container {
    background: #eef1f5;
}

/* Cluster contents, shown when a cluster will not split — venues sharing a
   coordinate, or a cluster already at max zoom. Replaces markercluster's
   spiderfy, which MapLibre has no equivalent for. */
.cluster-list, .globe-list {
    list-style: none;
    margin: 0;
    padding: 12px 14px;
    max-height: 240px;
    overflow-y: auto;
}
.cluster-list li, .globe-list li { padding: 4px 0; font-size: 14px; line-height: 1.35; }
.globe-more { color: #9ca3af; font-size: 13px; }

/* ---------------------------------------------------------------------------
   THE HOMEPAGE GLOBE'S SKY

   MapLibre draws the area outside the sphere transparent, so "space" is not
   something the map renders -- it is a layer sitting behind it. That is also
   why there is no zoom handling here: as you zoom in the sphere grows past the
   viewport and covers the stars on its own, with no opacity to manage and no
   listener on move.

   MapLibre has no `star-intensity`. That property is Mapbox's, and this build
   does not carry it -- checked before reaching for canvas.

   These rules live in listing.css because globe.blade.php already pushes that
   file for the shared popup styling; a second stylesheet would be a second
   request for about twelve lines.
--------------------------------------------------------------------------- */
.globe-stage {
    position: relative;
    /* HEIGHT LIVES HERE, NOT IN TAILWIND. The blade carried
       `h-[420px] sm:h-[520px]`, and `sm:h-[520px]` is not in the compiled
       app.css at all -- 520px appears nowhere in that file -- so the globe has
       silently been 420px on every breakpoint, desktop included. An arbitrary
       Tailwind class only exists if the build ran after it was written, and
       this one never did. Kept out of Tailwind entirely rather than rebuilt,
       so the globe's size cannot quietly detach from the rest of its styling
       again. 640px is Tailwind's own `sm`. */
    height: 420px;
    /* Also the loading state. The block used to be bg-gray-100 until the engine
       arrived, which read as a hole in the page rather than as a deliberate
       frame; this reads as sky from the first paint. */
    background: radial-gradient(ellipse at 50% 45%, #101a33 0%, #070b16 55%, #03050b 100%);
}
@media (min-width: 640px) {
    .globe-stage { height: 520px; }
}
.globe-stars {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;   /* a canvas is inline by default, which leaves a baseline gap */
}
/* DOUBLED, for the second time in this file, and for the same reason.
   MapLibre puts its own `maplibregl-map` class on whatever container it is
   given, and maplibre-gl.css declares `position: relative` on it. That sheet is
   injected into <head> at runtime by globe.js, so it always lands after this
   file and beats a single-class rule here on source order. A plain
   `.globe-map { position: absolute }` computed as `relative`, the absolutely
   positioned canvas then gave the container no height, and the globe rendered
   into a 1120x0 box -- a starfield with nothing in front of it. Anything set on
   a map CONTAINER has to out-specify that sheet. */
.globe-map.globe-map,
.globe-map .maplibregl-canvas-container,
.map-container .maplibregl-map,
.map-container .maplibregl-canvas-container {
    position: absolute;
    inset: 0;
    /* Transparent, against the `background: #eef1f5` set on .maplibregl-map and
       .maplibregl-canvas-container above. That grey is deliberate and STAYS for
       the listing and venue maps -- it is what stopped the globe there showing a
       red void in the corners. Here it would paint straight over the starfield,
       which is the one place the void is the point. Scoped by .globe-map so the
       two cases cannot be confused, and doubled for the same source-order
       reason as everything else that touches a map container. */
    background: transparent;
}

/* Attribution over space. OpenFreeMap and OSM attribution is required and stays
   fully legible — this only swaps the white card for the sky it sits on, since
   a white box in the corner of a starfield reads as a rendering fault. Scoped to
   .globe-map: the listing and venue maps keep the default, which is correct
   against their light background. */
.globe-map .maplibregl-ctrl-attrib {
    background: rgba(7, 11, 22, 0.72);
    color: #c3d0e6;
}
.globe-map .maplibregl-ctrl-attrib a,
.globe-map .maplibregl-ctrl-attrib a:hover {
    color: #e2e9f6;
}
.globe-map .maplibregl-ctrl-attrib-button {
    filter: invert(1) brightness(1.6);
}

/* ---------------------------------------------------------------------------
   MAP WIDEN CONTROL (11 Sep 2026)

   The map sits in a 6/12 column beside the listing. Pressing the arrow on its
   left edge collapses the listing column and lets the map take the whole row.

   DESKTOP ONLY, and the media query is the guard rather than a JS check: below
   sm the map is `fixed` and full-screen already (see .map-container above), so
   a widened state there is meaningless. The button itself is hidden with
   Tailwind's `hidden sm:flex`; this keeps the layout rules from applying even
   if something toggles the class at a narrow width.

   Width is driven by the ROW, not by the two columns individually, so there is
   one source of truth for the state and the columns cannot disagree. !important
   is needed because the widths it overrides are Tailwind utilities of equal
   specificity that appear later in the cascade.
   --------------------------------------------------------------------------- */
@media (min-width: 640px) {
    [data-map-row].map-widened [data-list-col] {
        display: none;
    }

    [data-map-row].map-widened [data-map-col] {
        width: 100% !important;
    }

    /* The arrow points left to say "grow this way". Once widened, the only
       thing it can do is go back, so it turns to point right. */
    [data-map-row].map-widened .map-widen-icon {
        transform: rotate(180deg);
    }
}

/* The control itself. Deliberately NOT Tailwind utilities -- see the note in
   partials/map.blade.php: app.css is a Mix build and z-[1000] / border-l-0 are
   not in it, so relying on a rebuild would have shipped an unstyled button. */
.map-widen-btn {
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 1000;
    width: 1.75rem;
    height: 3.5rem;
    align-items: center;
    justify-content: center;
    border: 1px solid #e5e7eb;
    border-left: 0;
    border-radius: 0 0.5rem 0.5rem 0;
    background: #fff;
    box-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -4px rgba(0, 0, 0, .1);
    color: #4b5563;
    cursor: pointer;
    transition: color .15s ease, background-color .15s ease;
}

.map-widen-btn:hover {
    background: #f9fafb;
    color: #e3342f;
}

.map-widen-icon {
    width: 1rem;
    height: 1rem;
    transition: transform .3s ease;
}


/* ---------------------------------------------------------------------------
   THE LISTING MAP GETS THE SAME SKY

   It is the same globe as the homepage's when you zoom out far enough, so the
   grey void was the odd one out once the homepage had stars. The map element
   inside is already `absolute inset-0`, and the canvas is its previous sibling:
   both are positioned, so document order alone puts the stars behind the map
   and neither needs a z-index.

   The gradient sits on .map-container rather than on the canvas so it is also
   the LOADING colour — it replaces the bg-gray-100 the container used to carry,
   which is why there is no grey flash before the tiles arrive.
--------------------------------------------------------------------------- */
.map-container {
    background: radial-gradient(ellipse at 50% 45%, #101a33 0%, #070b16 55%, #03050b 100%);
}
.map-stars {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;   /* a canvas is inline by default, which leaves a baseline gap */
}
/* ATTRIBUTION IS DELIBERATELY LEFT ALONE HERE, unlike on the homepage globe.
   That block is space the whole time it is on screen, so a dark chip belongs.
   This map opens at zoom 13 — a light city map — and the sky is the edge state
   you reach only by zooming right out. Styling the attribution for the rare
   state would put a dark chip on a light map for almost every visitor. It stays
   legible in both, which is the requirement; matching the sky is not. */
