/*
 * Kreezalid — search results on a map.
 *
 * Everything is scoped under .kz-map or .kz-results, and nothing here selects a class
 * the themes already use. That is deliberate: this stylesheet is loaded onto the
 * category and search pages of a live marketplace, and it must be able to add a map
 * column without reaching into the page around it.
 *
 * No @layer: the themes ship unlayered CSS, and an unlayered rule beats anything in a
 * layer whatever its specificity.
 */

.kz-map-page {
    --kz-map-radius: 14px;
    --kz-map-ink: #17222e;
    --kz-map-muted: #6b7280;
    --kz-map-shadow: 0 2px 6px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .08);
    --kz-map-shadow-lg: 0 14px 38px -10px rgba(0, 0, 0, .28);
}

/* ------------------------------------------------------------- page head */

.kz-map-page .kz-map-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 14px;
}

/* The search form is the theme's own. It is given a shape here, not a redesign:
   a pill that fills the row, with its inner grid left to the theme. */
.kz-map-page .kz-search-form {
    flex: 1 1 auto;
    min-width: 0;
    padding: 6px 8px 6px 18px;
    border-radius: 999px;
    background: #f7f7f7;
}

/* Emptied when its form has moved into the dialog: an empty pill is a hole. */
.kz-map-page .kz-search-form:empty { display: none; }

.kz-map-page .kz-search-form form {
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
}

.kz-map-page .kz-map-filters { flex: 0 0 auto; }

.kz-map-page .kz-map-filters .toggle-filters {
    border: 0;
    border-radius: 999px;
    background: #f7f7f7;
    padding: 11px 20px;
    white-space: nowrap;
}

/* The button that opens the form on a phone. Hidden until the script decides the
   viewport is small, so it is never offered next to the form it duplicates. */
.kz-map-page .kz-search-open {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    margin-bottom: 14px;
    padding: 11px 18px;
    border: 0;
    border-radius: 999px;
    background: #f7f7f7;
    color: var(--kz-map-ink, #17222e);
    font-weight: 600;
}

.kz-map-page .kz-search-open[hidden] { display: none; }

/*
 * The categories, as one scrolling row per level.
 *
 * A row that scrolls rather than a list that wraps: past a handful of them, wrapping
 * pushes the results off the first screen.
 *
 * The platform renders the tree NESTED — the <li> of the branch you are in also holds
 * its children's <ul> — so each level gets its own row only once the script has
 * unwrapped it (see unnestCategories). The `> ul` below is what each of those rows
 * becomes; the column rule under it is what keeps the un-unwrapped shape survivable
 * in the meantime, by stopping a nested list from stretching its parent's chip.
 */
.kz-map-page .kz-map-categories {
    margin-bottom: 16px;
}

.kz-map-page .kz-map-categories > ul {
    display: flex;
    flex-wrap: nowrap;
    gap: 10px;
    margin: 0 0 8px;
    padding: 0;
    list-style: none;
    overflow-x: auto;
    scrollbar-width: none;
}

.kz-map-page .kz-map-categories > ul:last-child { margin-bottom: 0; }
.kz-map-page .kz-map-categories > ul::-webkit-scrollbar { display: none; }

.kz-map-page .kz-map-categories li {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
}

/* A child row reads as a child: same chip, one size down. */
.kz-map-page .kz-map-categories > ul.result_subcategory_list a {
    padding: 5px 12px;
    font-size: 13px;
}

.kz-map-page .kz-map-categories a {
    display: block;
    padding: 6px 14px;
    border: 1px solid rgba(0, 0, 0, .12);
    border-radius: 10px;
    background: #fff;
    color: inherit;
    font-size: 14px;
    text-decoration: none;
    white-space: nowrap;
}

.kz-map-page .kz-map-categories a:hover,
.kz-map-page .kz-map-categories a.active {
    border-color: var(--kz-map-ink, #17222e);
    background: var(--kz-map-ink, #17222e);
    color: #fff;
}

@media (max-width: 899px) {
    .kz-map-page .kz-map-head { margin-bottom: 0; }
}

/* ---------------------------------------------------------------- layout */

/* Results on the left, map on the right, the map staying put as the list scrolls.
   `sticky` only works while no ancestor between it and the scroll root clips its
   overflow, which is why the map lives directly in this grid and not inside the
   results column. */
@media (min-width: 900px) {
    .kz-map-page .kz-map-layout {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 42%);
        column-gap: 24px;
        align-items: start;
    }

    .kz-map-page .kz-map-layout.kz-map--collapsed {
        grid-template-columns: minmax(0, 1fr) 0;
        column-gap: 0;
    }

    /* The map's half of the row is the constraint on how many cards fit. With it
       hidden there is room for four, and leaving three would waste the space the
       visitor just asked for. */
    .kz-map-page .kz-map-layout.kz-map--collapsed .kz-results-grid {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }

    .kz-map-page .kz-map {
        position: sticky;
        top: 16px;
        height: calc(100vh - 32px);
        margin: 16px 0;
    }

    .kz-map-layout.kz-map--collapsed .kz-map {
        opacity: 0;
        pointer-events: none;
        transform: translateX(16px);
    }
}

/*
 * On a phone the map is the backdrop and the results are a sheet over it.
 *
 * It used to be neither: the map comes after the results in the document, so on a
 * single column it landed at the very bottom of the page — around 1,960px down on a
 * category page, which is to say never seen. Ordering it to the top of the column
 * moves nothing in the markup, and `sticky` keeps it there while the sheet scrolls
 * over it, exactly as the desktop map holds its place beside the list.
 *
 * Both blocks bleed past the container's 15px gutter so the map and the sheet reach
 * the edges of the screen; the sheet puts the gutter back as its own padding.
 */
@media (max-width: 899px) {
    .kz-map-page .kz-map-layout {
        display: flex;
        flex-direction: column;
    }

    /*
     * The height here is only what the map has before the script measures the page.
     * What it has to be is "short enough that the sheet shows without scrolling",
     * and how short that is depends on how tall the theme's own page header is —
     * 313px above the map on the search page, 519px on a category page of the same
     * marketplace. See sizeMapForSheet().
     */
    .kz-map-page .kz-map {
        order: -1;
        position: sticky;
        top: 0;
        height: 42vh;
        margin: 0 -15px;
        border-radius: 0;
    }

    .kz-map-page .kz-results {
        position: relative;
        z-index: 2;
        min-height: 46vh;
        margin: -26px -15px 0;
        padding: 24px 15px 0;
        border-radius: 22px 22px 0 0;
        background: #fff;
        box-shadow: 0 -10px 26px -14px rgba(0, 0, 0, .3);
    }

    /* The grab handle. Decoration, not a control: the sheet is moved by scrolling
       the page, which is what a visitor's thumb does there anyway. */
    .kz-map-page .kz-results::before {
        content: "";
        position: absolute;
        top: 10px;
        left: 50%;
        width: 44px;
        height: 5px;
        margin-left: -22px;
        border-radius: 999px;
        background: #d8dbe0;
    }
}

.kz-map-page .kz-results { min-width: 0; }

.kz-map-page .kz-results-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 24px;
}

@media (min-width: 1400px) {
    .kz-map-page .kz-results-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* One across on a phone. Two made each card too small to read at a glance, which
   defeats the point of lifting them over the map in the first place. */
@media (max-width: 599px) {
    .kz-map-page .kz-results-grid {
        grid-template-columns: minmax(0, 1fr);
        gap: 18px;
    }
}

/* The cards inside the grid are the platform's own, and the themes size them for a
   grid row: a percentage width, a float, a margin. Dropped into a grid cell that
   is already the right width, those rules make a card narrower than its cell and then
   clip whatever sticks out. The cell decides the width here; the card fills it. */
.kz-map-page .kz-results-grid > .results_list_item {
    width: 100%;
    max-width: 100%;
    min-width: 0;
    margin: 0;
    padding: 0;
    float: none;
    overflow: visible;
}

.kz-map-page .kz-results-grid > .results_list_item > * {
    width: 100%;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0;
}

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

.kz-map {
    position: relative;
    min-width: 0;
    overflow: hidden;
    border-radius: var(--kz-map-radius);
    background: #e8edf0;
    box-shadow: 0 2px 12px -4px rgba(0, 0, 0, .1);
    transition: opacity .25s ease, transform .25s ease;
}

.kz-map__canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.kz-map--fullscreen {
    position: fixed !important;
    inset: 20px !important;
    height: auto !important;
    margin: 0 !important;
    z-index: 10000;
    box-shadow: var(--kz-map-shadow-lg);
}

body.kz-map-locked { overflow: hidden; }

.kz-map__fullscreen {
    position: absolute;
    top: 14px;
    right: 14px;
    z-index: 900;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    padding: 0;
    border: 1px solid rgba(0, 0, 0, .06);
    border-radius: 10px;
    background: #fff;
    color: var(--kz-map-ink);
    cursor: pointer;
    box-shadow: var(--kz-map-shadow);
}

.kz-map__fullscreen:hover { background: #f6f7f9; }
.kz-map__fullscreen svg { width: 17px; height: 17px; }

/* --------------------------------------------------------------- markers */

/* A price tag rather than a pin: on a page of results the number is what a visitor
   is comparing, and it reads without a click. */
.kz-map__pin {
    display: inline-flex;
    align-items: center;
    padding: 6px 12px;
    border: 1px solid rgba(0, 0, 0, .05);
    border-radius: 999px;
    background: #fff;
    color: var(--kz-map-ink);
    font-size: 13px;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
    box-shadow: var(--kz-map-shadow);
    cursor: pointer;
    transition: transform .18s cubic-bezier(.16, 1, .3, 1), background .18s ease, color .18s ease;
}

.leaflet-marker-icon:hover .kz-map__pin,
.leaflet-marker-icon.is-hovered .kz-map__pin,
.leaflet-marker-icon.is-open .kz-map__pin {
    transform: scale(1.1);
    background: var(--kz-map-ink);
    color: #fff;
    z-index: 1000;
}

.kz-map__cluster {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border: 1px solid rgba(0, 0, 0, .06);
    border-radius: 999px;
    background: #fff;
    color: var(--kz-map-ink);
    font-size: 14px;
    font-weight: 700;
    box-shadow: var(--kz-map-shadow);
}

.leaflet-div-icon { background: transparent; border: 0; }
.marker-cluster, .marker-cluster div { background: transparent; border: 0; box-shadow: none; }

/* ----------------------------------------------------------------- popup */

.kz-map .leaflet-popup-content-wrapper {
    padding: 0;
    border-radius: var(--kz-map-radius);
    box-shadow: var(--kz-map-shadow-lg);
    overflow: hidden;
}

.kz-map .leaflet-popup-content { margin: 0; width: 260px !important; }

.kz-map__card { display: block; color: inherit; text-decoration: none; }
.kz-map__card:hover { color: inherit; text-decoration: none; }

.kz-map__card-media { display: block; height: 150px; background: #f1f2f4; }
.kz-map__card-media img { width: 100%; height: 100%; object-fit: cover; display: block; }

.kz-map__card-body { display: block; padding: 12px 14px 14px; }

.kz-map__card-title {
    display: -webkit-box;
    overflow: hidden;
    margin-bottom: 4px;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.35;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.kz-map__card-place { display: block; font-size: 12px; color: var(--kz-map-muted); }
.kz-map__card-price { display: block; margin-top: 6px; font-size: 14px; font-weight: 700; }

/* ---------------------------------------------------------------- toggle */

.kz-map__toggle {
    position: fixed;
    bottom: 24px;
    left: 50%;
    z-index: 950;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 12px 20px;
    border: 0;
    border-radius: 999px;
    background: var(--kz-map-ink);
    color: #fff;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transform: translateX(-50%);
    box-shadow: var(--kz-map-shadow-lg);
    transition: transform .18s ease, background .18s ease;
}

.kz-map__toggle:hover { transform: translateX(-50%) translateY(-2px); background: #000; }

@media (max-width: 899px) {
    .kz-map__toggle { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .kz-map, .kz-map__pin, .kz-map__toggle { transition: none; }
}

/* ------------------------------------------------------- filters dialog */

/*
 * The contents are the theme's own filter sidebar, moved into a dialog. It is built
 * for a narrow column inside a grid row, so in a dialog its rows keep the
 * negative margins of a grid that is no longer there and its checkboxes keep the
 * absolute positioning that put them in a gutter this dialog does not have — which
 * is why they ended up outside it, in the page behind.
 *
 * Everything below puts the block back into normal flow. Nothing reimplements a
 * filter: a filter added to the platform still appears here on its own.
 */

.kz-filters-modal .modal-dialog {
    width: auto;
    max-width: 720px;
    margin: 24px auto;
}

.kz-filters-modal .modal-content {
    border: 0;
    border-radius: 16px;
    box-shadow: 0 20px 60px -20px rgba(0, 0, 0, .35);
}

.kz-filters-modal .modal-header {
    padding: 20px 24px;
    border-bottom: 1px solid #eceef2;
}

.kz-filters-modal .modal-body {
    max-height: 70vh;
    padding: 20px 24px;
    overflow-y: auto;
}

.kz-filters-modal .modal-footer {
    padding: 16px 24px;
    border-top: 1px solid #eceef2;
}

/* A grid that is not in a row: drop the negative margins it inherits. */
.kz-filters-modal .row {
    margin-left: 0;
    margin-right: 0;
}

.kz-filters-modal [class*="col-"] {
    width: 100%;
    padding-left: 0;
    padding-right: 0;
    float: none;
}

/*
 * The checkbox belongs beside its label, and the row that holds them is the
 * CONTAINER, not the label.
 *
 * The box is a sibling of its label, never a child of it: every storefront form goes
 * through the app's FormHelper (App\View\Helper\FormHelper), which emits
 * `<div class="form-check"><input class="form-check-input"><label>...</label></div>`.
 *
 * Making the label the flex row instead is what put the box on a line of its own:
 * `display: flex` is block-level, so the label began a new line under the inline
 * input, and the `gap` meant to separate box from text landed between the text and
 * its result count — "Debutants     (3)", one line below its checkbox.
 *
 * Both classes are matched because the container carries both: the FormHelper names it
 * `form-check` and the field type appends `checkbox`.
 */
.kz-filters-modal .checkbox,
.kz-filters-modal .form-check,
.kz-filters-modal .radio {
    /* The control's own size, which the theme sets. Named so the alignment below
       reads as an equation rather than as a magic number. */
    --kz-box: 20px;

    display: flex;
    align-items: flex-start;
    gap: 10px;
    position: relative;
    margin: 0 0 10px;
    padding-left: 0;
    line-height: 1.4;
}

/*
 * A label that wraps must wrap inside its own column rather than push the box away,
 * hence `min-width: 0` beside the grow.
 */
.kz-filters-modal .checkbox label,
.kz-filters-modal .form-check label,
.kz-filters-modal .radio label {
    flex: 1 1 auto;
    min-width: 0;
    padding-left: 0;
    margin: 0;
    font-weight: 400;
    line-height: 1.4;
    cursor: pointer;
}

/*
 * Two things move the box off its label, and only one of them is layout.
 *
 * The theme nudges the control down with `transform: translateY(5px)` — which suits
 * its own sidebar, where the box sits in a gutter. A transform is painted after
 * layout, so flex centred the box and the theme then dropped it 5px: aligned in the
 * box model, visibly low on screen. It has to go before any alignment can hold.
 *
 * Then the row is aligned on the label's FIRST LINE, not on the label as a whole:
 * `align-items: center` reads well while every option is one line, and drops the box
 * into the middle of the paragraph as soon as one wraps — 22px down on a narrow
 * screen, which is where option titles do wrap. Hence flex-start plus the half
 * difference between the line box and the control.
 */
.kz-filters-modal .checkbox input[type="checkbox"],
.kz-filters-modal .radio input[type="radio"],
.kz-filters-modal input[type="checkbox"],
.kz-filters-modal input[type="radio"] {
    position: static;
    float: none;
    flex: 0 0 auto;
    transform: none;
    margin: calc((1.4em - var(--kz-box, 20px)) / 2) 0 0;
}

/*
 * `.filter_title` is a `<span>`, so its vertical margins are ignored and it shares a
 * line box with whatever is positioned over it — which on the price block is the
 * slider's own value bubble, sitting absolutely above its handle. "Prix" and "25 EUR"
 * were printed on top of each other. A block of its own separates them.
 */
.kz-filters-modal .filter_title,
.kz-filters-modal h3,
.kz-filters-modal h4 {
    display: block;
    margin: 22px 0 10px;
    font-size: 15px;
    font-weight: 600;
}

/*
 * Room above the slider for those bubbles. Measured, not guessed: the bubble is
 * absolutely positioned and its top lands 44px above the slider's own top, so the
 * clearance has to exceed that or the title is overlapped again.
 *
 * The theme spaced this block with two <br>s, which are redundant — and useless
 * against an absolutely positioned box — once the title is a block of its own.
 */
.kz-filters-modal .price_filter_side { margin-bottom: 26px; }
.kz-filters-modal .price_filter_side br { display: none; }
.kz-filters-modal .price_filter_side #price-ranger-slider { margin-top: 56px; }

.kz-filters-modal .filter_title:first-child,
.kz-filters-modal h3:first-child,
.kz-filters-modal h4:first-child { margin-top: 0; }

/* The category tree at the top of the sidebar reads as a row of chips here. */
.kz-filters-modal .result_category_list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 18px;
    padding: 0;
    list-style: none;
}

.kz-filters-modal .result_category_list li { margin: 0; }

.kz-filters-modal .result_category_list a {
    display: block;
    padding: 7px 14px;
    border: 1px solid rgba(0, 0, 0, .12);
    border-radius: 999px;
    font-size: 14px;
    text-decoration: none;
    white-space: nowrap;
}

/* The platform renders its own submit inside the facets and the dialog has its own
   in the footer; showing both offers the same action twice. */
.kz-filters-modal #listingFilters [type="submit"],
.kz-filters-modal #formFiltersSubmitButton { display: none; }
