/* ChatGO — la carte publique des chats.
 *
 * Loaded after style.css and only by carte.html. Everything the two pages share — the
 * palette, the square panels, the hard offset shadows, the stepped motion — lives in
 * style.css and is *not* repeated here. This file adds exactly what the map page needs
 * and nothing else, so the two pages cannot drift apart on the shared half.
 *
 * The map is the one place where a third party's pixels are on our page: the tiles are
 * fetched by the visitor's browser from OpenStreetMap, not from chatgo.sideral.ch. They
 * are therefore pushed towards the site's palette with a filter and coarsened into
 * blocks, because a crisp modern basemap next to an 8-bit cat face reads as two
 * different products stapled together.
 */

/* --- the map ------------------------------------------------------------- */

/* The frame is the same square panel as every .card on the site: 2 px of ink, one hard
   shadow, no radius. The map itself sits inside it with 2 px of paper showing, so the
   tiles end on a clean line instead of bleeding to the shadow. */
.map-frame {
    border: var(--border) solid var(--ink);
    box-shadow: var(--hard) var(--hard) 0 var(--ink);
    background: var(--card);
    padding: 2px;
    /* The pixelate overlay and the fallback panel are positioned against this frame, and
       the z-index creates the stacking context that keeps Leaflet's own z-indexes inside
       the map instead of over the page's sticky header. */
    position: relative;
    z-index: 0;
}

#map {
    height: clamp(340px, 68vh, 660px);
    background: #E7EEE3;   /* the app's land green: the colour before a single tile lands */
    position: relative;    /* Leaflet measures this box, so it must not be a static one */
    z-index: 0;            /* the sticky header is z-index 10; the map stays under it */
}

/* Leaflet writes its own font and its own link colour into its panes; both are pulled
   back to the site's rather than left at Leaflet's defaults. */
#map, .leaflet-container {
    font-family: inherit;
    font-size: 13px;
    background: #E7EEE3;
}
.leaflet-container a { color: var(--pink-deep); }

/* The tiles: the site's palette, in blocks.
 *
 * The filter is doing a duotone-ish push — the basemap's greens go sage, its water and
 * roads go towards the page's warm cream and pink, and the white space stops shouting.
 * The second step coarsens the result: a backdrop-filter on this pass-through overlay
 * samples the tiles *underneath* it and re-emits them blurred with a hard contrast
 * curve, which snaps the softness back into flat blocks. The overlay has no pointer
 * events, so panning, zooming and clicking go straight through to the map.
 *
 * Both properties are decoration. Where they are unsupported the tiles are simply
 * themselves, and the page is still a map. */
.map-frame .leaflet-tile-pane {
    filter: saturate(.68) brightness(1.06) contrast(.94) sepia(.10) hue-rotate(-6deg);
}
.pixelate {
    position: absolute;
    inset: 2px;                /* the frame's own padding: the overlay covers tiles, not border */
    z-index: 2;                /* above the tiles, below Leaflet's controls (which are 1000
                                  inside #map, and #map is z-index 0 in this stacking context) */
    pointer-events: none;
}
@supports (backdrop-filter: blur(1px)) {
    .pixelate { backdrop-filter: blur(1.6px) contrast(1.7) saturate(1.05); }
}

/* Leaflet's zoom buttons, redrawn as two squares of the site's chrome.
 *
 * The selectors are long on purpose. Leaflet adds `leaflet-touch` to the container on any
 * touch-capable browser — which is every browser a phone or a laptop runs — and ships
 * `.leaflet-touch .leaflet-bar a { width: 30px; height: 30px }`. That has exactly the
 * same specificity as one's first instinct, `.leaflet-control-zoom a`, and Leaflet's
 * stylesheet is loaded *after* this one (the page needs its CSS before it can size the
 * container), so the obvious selector loses and the buttons come out 30 px. Adding the
 * `.leaflet-bar` class to the chain is what makes these win, and it was verified in the
 * browser rather than assumed.
 *
 * Leaflet's own `.leaflet-bar a + a` also puts a 1 px separator *inside* the second
 * button's box; the site's border is 2 px and its shadow 4 px, so the separator is
 * removed and a real gap put between the squares, or the two shadows overlap and the
 * buttons read as one misaligned blob. */
.leaflet-touch .leaflet-bar .leaflet-control-zoom a,
.leaflet-touch .leaflet-bar a.leaflet-control-zoom-in,
.leaflet-touch .leaflet-bar a.leaflet-control-zoom-out,
.leaflet-control-zoom a {
    width: 36px;
    height: 36px;
    line-height: 32px;
    font-size: 21px;
    font-weight: 700;
    background: var(--card);
    color: var(--ink);
    border: var(--border) solid var(--ink);
    box-shadow: 2px 2px 0 var(--ink);
    border-radius: 0;
    text-align: center;
}
.leaflet-touch .leaflet-bar a.leaflet-control-zoom-out,
.leaflet-control-zoom a + a {
    margin-top: 8px;
    border-top: var(--border) solid var(--ink);   /* undo Leaflet's 1px separator */
}
.leaflet-control-zoom a:hover { background: var(--pink); color: var(--ink); }
.leaflet-touch .leaflet-bar { border: 0; box-shadow: none; border-radius: 0; }
.leaflet-bar { border: 0; box-shadow: none; border-radius: 0; }

/* Attribution: required by the tile source, kept small and out of the way of the cats. */
.leaflet-control-attribution {
    background: rgba(255, 247, 243, .88);
    border: var(--border) solid var(--ink);
    border-right: 0;
    border-bottom: 0;
    padding: 2px 6px;
    font-size: 11px;
    color: var(--text-secondary);
}
.leaflet-control-attribution a { color: var(--text-secondary); }

/* --- the cats ------------------------------------------------------------ */

/* A marker is a pixel sprite beside an optional count chip.
 *
 * The sprite must not be smoothed, and the flex box is what puts the chip next to it
 * rather than over the cat's face. Leaflet gives the box the size it was told in
 * `iconSize()` in carte.js — those two numbers are a pair and have to be changed
 * together, which is why both files point at each other in a comment.
 *
 * The drop-shadow is the sprite's halo: a pale cat over white water or a pale road is
 * otherwise a cat nobody sees. */
.leaflet-marker-icon { background: none; border: 0; }
.cat-marker {
    display: flex;
    align-items: center;
    gap: 3px;                    /* must match GAP in carte.js */
    image-rendering: pixelated;
    filter: drop-shadow(1px 1px 0 rgba(59, 42, 74, .32));
    transition: transform .08s steps(2, end);
    transform-origin: 50% 100%;
}
.cat-marker svg { display: block; image-rendering: pixelated; }
.leaflet-marker-icon:hover .cat-marker { transform: scale(1.12); }

/* The count, in the site's own plate vocabulary: square, ink outline, hard shadow, pink
   fill — the same object as `.pill`, one size down. It has to be readable at this size,
   which is exactly what the first version inside the SVG was not. */
.cat-chip {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 20px;                 /* must match CHIP_W in carte.js */
    height: 20px;
    background: var(--pink);
    border: var(--border) solid var(--ink);
    box-shadow: 2px 2px 0 var(--ink);
    color: var(--ink);
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
}

/* The name plate above an open cat. Square, ink-outlined, like everything else.
 *
 * Descendant-of-`.leaflet-container` selectors for the same reason as the zoom buttons:
 * Leaflet ships `.leaflet-popup-content-wrapper { border-radius: 12px }` and a rule of
 * equal specificity later in the cascade wins, which left the one rounded shape on the
 * whole site sitting on top of the map. Verified in the browser. */
.cat-pop {
    font-family: inherit;
    font-size: 13px;
    color: var(--ink);
}
.cat-pop b { font-size: 15px; letter-spacing: .5px; }
.cat-pop span { color: var(--text-muted); font-size: 12px; }
.leaflet-container .leaflet-popup-content-wrapper {
    background: var(--card);
    color: var(--ink);
    border: var(--border) solid var(--ink);
    box-shadow: var(--hard) var(--hard) 0 var(--ink);
    border-radius: 0;
}
.leaflet-popup-content { margin: 10px 12px; line-height: 1.4; }
.leaflet-container .leaflet-popup-tip-container { overflow: visible; }
.leaflet-container .leaflet-popup-tip {
    background: var(--card);
    border: var(--border) solid var(--ink);
    box-shadow: none;
}
.leaflet-popup-close-button { color: var(--text-muted) !important; }

/* --- the count and the fallback ------------------------------------------ */

/* The three facts, as three little plates rather than a sentence. */
.facts { display: flex; flex-wrap: wrap; gap: 10px; margin: 18px 0 16px; padding: 0; list-style: none; }
.facts li {
    background: var(--card);
    border: var(--border) solid var(--ink);
    box-shadow: 2px 2px 0 var(--ink);
    padding: 6px 12px;
    font-size: 13px;
}
.facts b { font-size: 15px; }
.facts .pip { background: var(--mint); }
.facts .pip-2 { background: var(--coin); }

/* When the API cannot be reached: a sentence, on the map, never a blank rectangle.
 *
 * The panel is a card in the middle, not a wash over everything. That is the difference
 * between "the cats could not be loaded" and "the map is broken": the streets, the lake
 * and the town names stay visible and usable around it, which is exactly what the copy
 * promises. `pointer-events: none` on the overlay is what keeps the map draggable through
 * it; only the card itself takes the pointer, so the retry link still works. */
.map-fallback {
    position: absolute;
    inset: 0;
    z-index: 3;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
    pointer-events: none;
}
.map-fallback.show { display: flex; }

.map-fallback .card {
    max-width: 46ch;
    pointer-events: auto;
    background: rgba(255, 255, 255, .96);
}
.map-fallback p { margin: 0 0 10px; color: var(--text-secondary); font-size: 14px; }
.map-fallback p:last-child { margin-bottom: 0; }
.map-fallback .lead { color: var(--ink); font-weight: 700; }

/* A retry is a link drawn as a chip, the same gesture as the download button. */
.retry {
    display: inline-block;
    padding: 6px 12px;
    background: var(--pink);
    border: var(--border) solid var(--ink);
    box-shadow: 2px 2px 0 var(--ink);
    color: var(--ink);
    font-weight: 700;
    font-size: 13px;
    text-decoration: none;
}
.retry:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }

/* The count of cats, while the fetch is in flight. */
.cat-count { color: var(--text-muted); font-size: 14px; }

@media (max-width: 640px) {
    #map { height: clamp(300px, 56vh, 460px); }
}
