/**
 * Plano — front end.
 *
 * Class names are Plano's own: Region Map's front.js grabs every
 * `.regionmap-container` on the page, and a shared class would have it
 * initialise our maps with its renderer. See plan §4.
 */

/*
 * The width is given; the height follows the shape.
 *
 * A map fills the column, the container, the page — whatever it was put in. What
 * it should be *tall* is not a second thing to decide but a fact about the area.
 * `front.js` projects the drawn shapes and writes the ratio here.
 *
 * The fallback is what the box looks like for the moment before the shapes
 * arrive, and nothing else. A page that wants another height says so with the
 * block's Dimensions panel (below), or a stylesheet with `--plano-aspect`; the
 * shape's ratio is a variable of its own (`--plano-shape-aspect`) so that it
 * never outranks that choice. `min-height` is a floor for a container with no
 * width of its own to derive from — a map you cannot see is still worse.
 */
.plano-map {
    width: 100%;
    aspect-ratio: var(--plano-aspect, var(--plano-shape-aspect, 4 / 3));
    min-height: 200px;
    background: #fff;
}

/*
 * Never taller than the screen.
 *
 * The ratio is right until the area is tall: Den Haag stands upright, and at
 * the full width of a page it came out 900 px high on an 875 px screen — a map
 * you cannot see whole, and whose drag fights the page's scroll. Capped, the
 * box goes wider than the shape and `fit()` centres the shape in it, which is
 * the trade the panel below already makes. Not a setting: a map taller than
 * the window is never what anybody wanted. Room is left for a theme's header.
 */
.plano-map {
    max-height: 80vh;
    max-height: 80svh;
}

/*
 * A height or a ratio from the block's Dimensions panel is on the frame, as
 * WordPress writes it (`height`, `min-height`, `aspect-ratio`). Then the frame decides and
 * the map fills it, without its own ratio, floor or cap: whoever chose 900px
 * meant it, and a theme's own `min-height` on the map (Hulp Rotterdam had one)
 * does not push it out of the frame.
 */
.plano-frame.has-aspect-ratio,
.plano-frame[style*="height"] {
    display: flex;
    flex-direction: column;
}

.plano-frame.has-aspect-ratio > .plano-map,
.plano-frame[style*="height"] > .plano-map {
    flex: 1 1 auto;
    aspect-ratio: auto;
    min-height: 0;
    max-height: none;
}

/*
 * The map's own element, so block and theme classes have one to go on. A border
 * from the block counts inside the width, and rounded corners round the map.
 */
.plano-frame {
    width: 100%;
    box-sizing: border-box;
}

.plano-frame[style*="border-radius"] {
    overflow: hidden;
}

.plano-map--failed {
    display: none;
}

/*
 * Leaflet draws labels as markers; these are text, not pins.
 *
 * The halo is written inline, per label, because it has to be the opposite of
 * the text — and the text is the opposite of the area it sits on. A fixed white
 * glow here was legible under a dark name and invisible under a light one, which
 * is the case that needs it: light text is what a dark area gets.
 */
.plano-map .plano-label {
    background: none;
    border: none;
    white-space: nowrap;
    pointer-events: none;
    font-weight: 500;
}

/*
 * Centred on its point, by the text itself.
 *
 * Leaflet positions the element and cannot centre it, because a name's width is
 * not known until it is rendered. Shifting the text by half of its own size is
 * the one measurement that is always available, and it is what keeps a long name
 * spread evenly around the place it belongs to rather than trailing off east of
 * it.
 */
.plano-map .plano-label span {
    display: inline-block;
    transform: translate(-50%, -50%);
}

/*
 * Leaflet paints its own grey behind the tiles, which is the wrong colour twice
 * over: a map with no tiles is not a grey box, and a bounded provider leaves
 * real gaps where that grey then shows. Transparent hands the question back to
 * `.plano-map`, which is white unless the style says otherwise — so a background
 * set in a style reaches the whole map rather than only its margins.
 */
.plano-map .leaflet-container {
    font: inherit;
    background: transparent;
}

.plano-missing {
    padding: 12px 16px;
    border: 1px dashed #d1d5db;
    border-radius: 8px;
    color: #6b7280;
}

/* --- The panel -------------------------------------------------------------
 *
 * Always a block of its own (`plano/panel`), placed where the editor wants it:
 * the map never opens one beside itself. Same content as a popup — plan §7 has
 * all three interactions rendering one template; only where it lands differs.
 *
 * At the width of its column, there once the map has something to say, and
 * with its own scroller, because a map of two thousand places would otherwise
 * be a page of two thousand rows, and hovering a pin scrolls this list, never
 * the page.
 */
.plano-panel {
    max-height: 80vh;
    max-height: 80svh;
    overflow-y: auto;
}

.plano-panel:not(.is-open) {
    display: none;
}

/*
 * The heading is sized here, not by the theme. A block theme styles `h3` for
 * an article, and in a column a third of the page wide "Zeeheldenkwartier"
 * came out in display type and was cut off after "Zeeheldenk".
 */
.plano-panel h3 {
    margin-top: 0;
    font-size: 1.25rem;
    line-height: 1.3;
    overflow-wrap: anywhere;
}

/*
 * A pin's tooltip through its pattern: a small card, not a line. Leaflet sets
 * `white-space: nowrap` on every tooltip, which is right for a name and turns
 * a pattern into one line running off the map.
 */
.leaflet-tooltip.plano-pin-tip {
    width: 260px;
    white-space: normal;
}

.plano-pin-tip > :first-child {
    margin-top: 0;
}

.plano-pin-tip > :last-child {
    margin-bottom: 0;
}

/* The pins on screen: a name per line, the address under it. */
.plano-panel-pins {
    margin: 0;
    padding: 0;
    list-style: none;
}

.plano-panel-pins li {
    padding: 8px 0;
    border-bottom: 1px solid #e5e7eb;
    line-height: 1.35;
    transition: background-color 120ms ease;
}

/*
 * Hovered, or the pin on the map is. The same wash as `.plano-legend-item`,
 * so pointing at something on the map feels the same wherever you do it.
 */
.plano-panel-pins li:hover,
.plano-panel-pins li.is-active {
    background: rgba(0, 0, 0, 0.05);
}

/*
 * A row whose pattern is on its way: a placeholder card in its place, as tall
 * as the first filled row measured — so the list neither flashes bare titles
 * nor jumps. Two bars for title and address, in the text colour at a low
 * opacity, so it suits any theme.
 */
.plano-panel-pins li.plano-panel-pin--waiting {
    position: relative;
    box-sizing: border-box;
    min-height: var(--plano-pin-height, 3.5em);
}

.plano-panel-pins li.plano-panel-pin--waiting > * {
    visibility: hidden;
}

.plano-panel-pins li.plano-panel-pin--waiting::before,
.plano-panel-pins li.plano-panel-pin--waiting::after {
    content: "";
    position: absolute;
    left: 0;
    height: 0.75em;
    border-radius: 0.375em;
    background: currentColor;
    opacity: 0.08;
    animation: plano-placeholder 1.4s ease-in-out infinite;
}

.plano-panel-pins li.plano-panel-pin--waiting::before {
    top: 12px;
    width: 60%;
}

.plano-panel-pins li.plano-panel-pin--waiting::after {
    top: calc(12px + 1.35em);
    width: 38%;
}

@keyframes plano-placeholder {
    50% {
        opacity: 0.16;
    }
}

@media (prefers-reduced-motion: reduce) {
    .plano-panel-pins li.plano-panel-pin--waiting::before,
    .plano-panel-pins li.plano-panel-pin--waiting::after {
        animation: none;
    }
}

/* Through the pattern. */
.plano-panel-pin-body {
    min-width: 0;
}

.plano-panel-pin-body > :first-child {
    margin-top: 0;
}

.plano-panel-pin-body > :last-child {
    margin-bottom: 0;
}

.plano-panel-pins li span {
    display: block;
    color: #6b7280;
    font-size: 0.875em;
}

.plano-panel-empty {
    color: #6b7280;
    font-style: italic;
}

.plano-popup h3 {
    margin: 0 0 8px;
    font-size: 1.1em;
}

/* --- The legend -------------------------------------------------------------
 *
 * Filled by the renderer from the list it drew, so the colours are the map's own
 * rather than a second calculation that will one day disagree.
 */

.plano-legend {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 12px 0;
}

/* Past a dozen entries a single column is a scroll, so it becomes a grid.
   At 342 municipalities a legend is the wrong tool, but it should still be
   usable rather than a mile long. */
.plano-legend--long {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 2px 16px;
    max-height: 320px;
    overflow-y: auto;
}

.plano-legend-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 3px 6px;
    border: 0;
    border-radius: 4px;
    background: none;
    color: inherit;
    font: inherit;
    font-size: 0.95em;
    text-align: left;
    cursor: pointer;
}

.plano-legend-item:hover,
.plano-legend-item.is-active {
    background: rgba(0, 0, 0, 0.05);
}

/* A group on a map that cannot be panned has nowhere to take you: hovering
   still lights its areas up, but the pointer should not promise a click. */
.plano-legend-item--static {
    cursor: default;
}

.plano-legend-swatch {
    flex: 0 0 14px;
    width: 14px;
    height: 14px;
    border-radius: 3px;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
}

.plano-legend-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Pins are inline SVG in a divIcon, so the wrapper must not add anything. */
.plano-map .plano-pin {
    background: none;
    border: none;
}

/*
 * The scalable layer. Leaflet positions the marker itself with a transform, so
 * growing one on hover has to happen a level below, or the pin walks off its
 * spot. A teardrop grows from its point, a dot from its middle.
 */
.plano-map .plano-pin-inner {
    display: block;
    position: relative;
    transition: transform 120ms ease;
    transform-origin: 50% 100%;
}

.plano-map .plano-pin--dot .plano-pin-inner {
    transform-origin: 50% 50%;
}

.plano-map .plano-pin svg {
    display: block;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
}

/*
 * The post's own icon, inside the marker's white circle. Positioned inline
 * from `front.js` because only the script knows the size the style asked for.
 */
.plano-map .plano-pin-badge {
    position: absolute;
    display: block;
    pointer-events: none;
}

.plano-map .plano-pin-badge img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.plano-map .plano-pin-badge .plano-pin-text {
    font-size: 100%;
}

/* Hovered here or in the panel: the same pin, said the same way. */
.plano-map .plano-pin.is-active .plano-pin-inner {
    transform: scale(1.3);
}

.plano-map .plano-pin.is-active svg {
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.45));
}

.plano-map .plano-cluster.is-active span {
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3), 0 0 0 4px rgba(255, 255, 255, 0.85);
}

.plano-map .plano-pin-text {
    display: block;
    line-height: 1;
    text-align: center;
    filter: drop-shadow(0 1px 1px rgba(255, 255, 255, 0.9));
}

/*
 * A cluster of pins: a disc with the count, in the pin colour of the style.
 * The colour comes in inline from `front.js`, because it is the style's and
 * not this sheet's. Sized as Region Map's drilldown sized it.
 */
.plano-map .plano-cluster {
    background: none;
    border: none;
}

.plano-map .plano-cluster span {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    border: 2px solid #fff;
    border-radius: 50%;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    color: #fff;
    font: 600 13px/1 system-ui, sans-serif;
}

/*
 * A map that failed, reported to whoever can do something about it.
 *
 * `.plano-map--failed` hides itself, which is right for a visitor and wrong for
 * an editor: a gap in a page is better than an error in one, but a gap nobody is
 * told about is a site that stays broken. The renderer only adds this second
 * class when the viewer can edit.
 */
.plano-map--failed.plano-map--reported {
    display: block;
    aspect-ratio: auto;
    height: auto;
    padding: 12px 16px;
    border: 1px dashed #d1d5db;
    border-radius: 8px;
    background: #fff;
    color: #6b7280;
    font-size: 0.9em;
}

/*
 * A Visual filter on a Plano map: a row of chips, icon and name.
 *
 * JetSmartFilters lists the options one per line, which for 25 categories is a
 * column that pushes the map off the screen. As chips that wrap they take two
 * or three lines above the map. The icons are the pins' own (see
 * `Content\JetFilters::visual_options()`), so a chosen chip is marked in the
 * pin colour.
 *
 * Only on filters pointed at Plano, by the provider attribute JetSmartFilters
 * puts on the list itself: other filters on the site are not ours to restyle.
 */
.jet-color-image-list[data-content-provider="plano"] fieldset {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

.jet-color-image-list[data-content-provider="plano"] .jet-color-image-list__row {
    margin: 0;
}

.jet-color-image-list[data-content-provider="plano"] .jet-color-image-list__item {
    display: block;
    margin: 0;
    cursor: pointer;
}

.jet-color-image-list[data-content-provider="plano"] .jet-color-image-list__button {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 30px;
    box-sizing: border-box;
    padding: 4px 10px;
    border: 1px solid #d1d5db;
    border-radius: 999px;
    background: #fff;
    font-size: 14px;
    line-height: 1.3;
    transition: border-color 120ms ease, background-color 120ms ease;
}

.jet-color-image-list[data-content-provider="plano"] .jet-color-image-list__button:hover {
    border-color: #9ca3af;
}

.jet-color-image-list[data-content-provider="plano"] .jet-color-image-list__input:checked + .jet-color-image-list__button {
    border-color: #b42318;
    background: #fef3f2;
}

.jet-color-image-list[data-content-provider="plano"] .jet-color-image-list__input:focus-visible + .jet-color-image-list__button {
    outline: 2px solid #b42318;
    outline-offset: 2px;
}

.jet-color-image-list[data-content-provider="plano"] .jet-color-image-list__decorator {
    display: inline-flex;
    margin: 0;
}

.jet-color-image-list[data-content-provider="plano"] .jet-color-image-list__image {
    display: inline-flex;
    width: 18px;
    height: 18px;
    padding: 0;
    border: 0;
}

.jet-color-image-list[data-content-provider="plano"] .jet-color-image-list__image img {
    width: 18px;
    height: 18px;
    object-fit: contain;
}

.jet-color-image-list[data-content-provider="plano"] .jet-color-image-list__label {
    padding: 0;
    font-size: inherit;
}

/*
 * A category without an icon: JetSmartFilters draws its own placeholder
 * there. The chip is then just the name, not a grey box beside it.
 */
.jet-color-image-list[data-content-provider="plano"] .jet-color-image-list__decorator:has(img[src*="jet-smart-filters/assets/images/placeholder.png"]),
.jet-color-image-list[data-content-provider="plano"] img[src*="jet-smart-filters/assets/images/placeholder.png"] {
    display: none;
}

/*
 * A clicked area keeps the browser's focus ring, and on an SVG path that ring
 * is the bounding box: a rectangle around the district that stays put while
 * the map pans. The shapes are not in the tab order (Leaflet gives them no
 * tabindex), so nobody reaches them by keyboard and nothing is lost.
 */
.plano-map path.leaflet-interactive:focus {
    outline: none;
}

/* The button back to the whole map, under Leaflet's zoom buttons and shaped like them. */
.plano-map .plano-reset a {
    display: flex;
    align-items: center;
    justify-content: center;
    color: inherit;
}
