/* A variable rather than a literal because the project list beside the map has to be
   exactly as tall: it is a flex sibling, so without a height of its own it would set
   the height of the row instead of taking it, and grow with the list rather than
   scrolling it. */
:root {
    --viewport-height: 100vh;
    --map-height: calc(var(--viewport-height) - (var(--footer) + var(--navbar)));
}
/* iOS Safari resolves 100vh to the *large* viewport — the height the page would have if
   the toolbars were retracted — so the bottom edge of a 100vh map, and the caption and
   Project List button pinned to it, end up underneath the back/forward bar. svh is the
   small viewport, measured with those toolbars showing.

   svh rather than dvh on purpose: dvh tracks the toolbars as they slide away, which would
   resize the map mid scroll and leave Leaflet holding a stale size. svh is a fixed number
   for the life of the page, and it makes the whole page — map plus footer — exactly one
   small viewport tall, so there is nothing to scroll and the toolbars stay put anyway. */
@supports (height: 100svh) {
    :root {
        --viewport-height: 100svh;
    }
}
#map {
    height: var(--map-height);
    cursor: default;
    width: 100%;
    z-index: 100;
}
.map-text {
    color: #7f7f7f;
    text-align: center;
    margin-bottom: 0rem !important;
}
.input-group{
    margin-bottom: 1rem;
}
/* Below this width the map runs full bleed under the fixed navbar — the page drops its
   navbar offset, the map takes that height back and the nav goes transparent — so the
   two read as one piece.

   Width only, deliberately. This used to be gated on (orientation: landscape) as well,
   which made the layout depend on the window *height*: a 945px wide window that happened
   to be taller than it was wide counted as portrait and snapped back to the boxed map, a
   few pixels below a 970px one that did not. setProjectMode() in map.jinja matches this
   query, because the side panel cannot be on screen while the navbar sits over it. */
@media (max-width: 970px) {
    .offset-navbar{
        margin-top: 0 !important;
    }
    /* The navbar offset is gone, so both are the viewport less the footer — written off
       --viewport-height rather than style.css's --full-page-height, which is still 100vh
       based and would put the bottom of the map back under the Safari toolbar. */
    .full-page{
        min-height: calc(var(--viewport-height) - var(--footer)) !important;
    }
    :root{
        --map-height: calc(var(--viewport-height) - var(--footer));
    }
    nav {
        background-color: transparent !important;
        padding-left: 44px !important;
        pointer-events: none;
    }
    nav > a > .dr-nik-text{
        display: none;
    }
    nav * {
        pointer-events: auto;
    }
    /* The rest of what this width changes — the sheet, the collapsed filter button, and
       the chrome they now sit over — is at the foot of this file. It has to come after the
       base rules it overrides: a media query adds no specificity, so up here
       .project-sheet{display: flex} would simply lose to the .project-sheet block further
       down. */
}

/* Still orientation gated: everything here is the short viewport case. A landscape phone
   has no vertical room for the full size caption, which is a question about height and
   not about how wide a desktop window is.

   The .offcanvas rules stay although the project list no longer uses one: navbar.html
   opens the nav menu in a Bootstrap offcanvas, and it is the same short viewport. */
@media (orientation: landscape) and (max-width: 970px) {
    .offcanvas{
        --bs-offcanvas-width: 80vw;
    }
    .offcanvas-header{
        padding: .5rem !important;
    }
    .offcanvas-body{
        padding: .5rem !important;
    }
    /* :not(.canvas) so the sheet copy keeps the side padding that stops its rows
       running into the screen edge. */
    .project-list:not(.canvas){
        padding: 0rem !important;
    }
    .map-container{
        margin-left: .5rem;
        margin-bottom: .5rem !important;
        left: 0 !important;
        right: 30%;
        transform: unset !important;
    }
    .highlight {
        font-size: small !important;
    }
    .map-text {
        white-space: normal;
        font-size: small;
        text-align: start;
    }
    .input-group-text{
        font-size: small;
    }
    label, select{
        padding: .2rem .5rem !important;
    }
}

@media (max-width: 570px){
    .map-text {
        white-space: normal;
        font-size: medium;
    }
    .highlight {
        font-size: medium !important;
    }
    /* The 3rem the caption used to need here was clearance for the Project List button,
       which is gone at this width — the sheet's own --sheet-peek offset replaces it. */
    .input-group-text{
        font-size: small;
    }
    label, select{
        padding: .2rem .5rem !important;
    }
}
.highlight{
    color: #1350a4;
    font-weight: 800;
    font-size: 1.2rem;
}
.filter-container {
    position: absolute;
    top: 0;
    right: 0;
    left: 10%;
    z-index: 500;
    margin: 1rem;
    display: flex;
    justify-content: flex-end;
    flex-direction: row;
    border-radius: 2rem;
    gap: 1rem;
    pointer-events: none;
}
.filter-container > .filter-list{
    pointer-events: auto;
}
@media (max-width: 1230px) {
    .filter-container {
        flex-direction: column;
        align-items: flex-end;
        gap: .3rem;
    }
}
/* The collapsed filter, shown only below 970px — see the foot of this file, which is also
   where it is positioned. Left bare like the navbar hamburger it sits beside; the only
   fill it ever takes is the one that says a filter is set. */
.filter-toggle{
    display: none;
}
.filter-toggle.is-active{
    color: #fff;
    background-color: var(--primary-color);
    border-color: var(--primary-color);
}
/* Hidden at zero via the [hidden] attribute, so the button is just "Filter" until there is
   a number worth showing. */
.filter-toggle-count{
    min-width: 1.25rem;
    margin-left: .4rem;
    padding: 0 .25rem;
    font-size: .75rem;
    font-weight: 700;
    line-height: 1.25rem;
    text-align: center;
    color: var(--primary-color);
    background-color: #fff;
    border-radius: 999px;
}
.table-tool{
    position: absolute;
    bottom: 0;
    right: 0;
    margin: 1rem;
    margin-bottom: 1.3rem;
    z-index: 502;
}
/* Animated rather than display:none/block so the 40vw panel — and the map next
   to it — ease open instead of snapping. Padding is animated too, otherwise
   border-box leaves a 1rem sliver at width 0. */
.project-list{
    display: block;
    width: 0;
    padding: 0;
    opacity: 0;
    visibility: hidden;
    overflow: hidden;
    transition: width var(--dur-slow) var(--ease-out),
                padding var(--dur-slow) var(--ease-out),
                opacity var(--dur-base) var(--ease-standard),
                visibility 0s linear var(--dur-slow);
}
.project-list.show{
    width: 40vw;
    padding: .5rem;
    opacity: 1;
    visibility: visible;
    transition: width var(--dur-slow) var(--ease-out),
                padding var(--dur-slow) var(--ease-out),
                opacity var(--dur-base) var(--ease-standard) var(--dur-fast),
                visibility 0s linear 0s;
}
/* In the sheet the panel takes its height from the sheet it sits in rather than from the
   map: flex:1 against a height the drag is rewriting every frame, which is what keeps the
   row list — and only the row list — absorbing the change. */
.project-list.canvas{
    width: 100%;
    height: auto;
    flex: 1;
    min-height: 0;
    padding: .5rem;
    opacity: 1;
    visibility: visible;
    overflow: hidden;
    transition: none;
}
/* ---- bottom sheet (below 970px; display:flex comes from the query above)

   The stops are px values project_sheet.js measures and writes onto :root, so a drag and
   the height it settles at are the same number. The values here are only what the first
   paint uses, before the script has run.

   Height rather than transform: translating a full height sheet is the cheaper animation,
   but it carries .project-list-footer — the pagination — off the bottom of the screen at
   every stop short of full. Animating the height lets the flex column below re-solve, so
   the footer stays on the visible bottom edge at half too. */
:root{
    --sheet-peek: 5.5rem;
    --sheet-half: 55svh;
    --sheet-full: 85svh;
}
.project-sheet{
    display: none;
    flex-direction: column;
    position: fixed;
    left: 0;
    right: 0;
    /* Above the footer rather than over it: a sheet at bottom:0 would cover it for good.

       --footer is the footer's measured height, published by footer_height.js — the 56px
       constant below it is only true while that text fits on one line, and a phone wraps it
       to three or four. Measuring is also what keeps the page one small viewport tall with
       nothing to scroll; on the constant it overflows, and a sheet pinned to the viewport
       does not travel with a footer that scrolls into view. */
    bottom: var(--footer);
    /* Over the map (100), the caption (500) and the Project List button (502), and under
       the navbar.

       Under the *navbar*, not under Bootstrap's 1045: nav is position:fixed with
       z-index:1000, which makes it a stacking context, and navbar.html puts the offcanvas
       menu inside it. The menu's own 1045 is therefore scoped to nav and never lifts it
       past nav's 1000 — so anything that has to sit below the menu has to sit below nav. */
    z-index: 600;
    height: var(--sheet-peek);
    overflow: hidden;
    background-color: #fff;
    border-radius: 1rem 1rem 0 0;
    box-shadow: 0 -2px 16px rgba(19, 80, 164, .18);
    transition: height var(--dur-slow) var(--ease-out);
}
.project-sheet[data-state="half"]{
    height: var(--sheet-half);
}
.project-sheet[data-state="full"]{
    height: var(--sheet-full);
}
/* Mid drag the height is written every frame from the pointer position, so there is
   nothing left for a transition to interpolate. */
.project-sheet.is-dragging{
    transition: none;
}
@media (prefers-reduced-motion: reduce) {
    .project-sheet{
        transition: none;
    }
}
.project-sheet-grabber{
    flex: 0 0 auto;
    padding: .6rem 0 .35rem;
    background: transparent;
    border: 0;
    /* Both are drag handles, so the browser must not claim the gesture for a scroll
       before the pointer handlers have seen it. */
    touch-action: none;
    cursor: grab;
}
.project-sheet-grabber:active{
    cursor: grabbing;
}
.project-sheet .all-projects-title{
    touch-action: none;
}
.project-sheet-handle{
    display: block;
    width: 2.5rem;
    height: .25rem;
    margin: 0 auto;
    /* Literal rather than --project-rule: that is declared on .all-projects, which is a
       sibling of the grabber and not an ancestor, so it would never reach here. */
    background-color: #c7ced9;
    border-radius: 999px;
}
/* The panel is shorter than its own content at peek and half. Only the row list may take
   up the slack — if the chrome shrinks too, the title creeps up out of the peek strip and
   the sort row half appears under it. Everything below the visible edge is clipped by the
   sheet's overflow, which is what makes the strip a strip without any markup of its own. */
.project-sheet .all-projects-title,
.project-sheet .all-projects-search,
.project-sheet .all-projects-controls,
.project-sheet .project-list-footer{
    flex-shrink: 0;
}
/* The sheet is the card here; the panel keeping its own rounded corners and shadow would
   draw a second one a few pixels inside it. */
.project-sheet .project-list{
    border-radius: 0;
    box-shadow: none;
    padding-top: 0;
}
/* Nothing behind the sheet should scroll when the rows run out — on iOS the page would
   otherwise rubber band under a sheet that is meant to be a fixed surface. */
.project-sheet .project-list-wrapper{
    overscroll-behavior: contain;
}
/* Tighter than the sidebar's: the peek strip is only as tall as this row, and every
   pixel it gives back is one the map keeps. Carries .project-list to outweigh the
   sidebar scale's own .project-list .all-projects-title further down the file. */
.project-sheet .project-list .all-projects-title{
    margin-bottom: .5rem;
}
/* The panel runs the shared list design from project_list.css — hence the
   all-projects class on its root — one size down, because it is a 40vw sidebar and
   not a full width page column. Everything below is either that smaller scale or
   the panel chrome the service page has no use for. */
.project-list{
    --project-year-col: 4.25rem;
    --project-gap: .9rem;
    margin: 0;
    /* Matches the map exactly, and is a height rather than a max-height so the row list
       below has something definite to take the remainder of. */
    height: var(--map-height);
    background-color: #fff;
    border-radius: .75rem;
    box-shadow: 0 1px 3px rgba(19, 80, 164, .08);
}
/* Column layout only once the panel is open: the closed one is a 0 width block
   mid-transition and has nothing to lay out. The header, search and sort sit above the
   scrolling rows and the pagination below them, which is what lets the row list take
   the height that is left instead of being told what it is. */
.project-list.show, .project-list.canvas{
    display: flex;
    flex-direction: column;
}
.project-list-wrapper {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-gutter: stable;
}
@media(width < 520px){
    #project-toggler > span {
        display: none;
    }
}

/* ---- sidebar scale */

.project-list .all-projects-title{
    font-size: 1.4rem;
    margin-bottom: .9rem;
}
.project-list .all-projects-count{
    font-size: .8rem;
}
.project-list .all-projects-search{
    max-width: none;
    margin-bottom: .75rem;
}
.project-list .all-projects-search input{
    padding: .35rem .25rem .45rem 1.75rem;
    font-size: .9rem;
}
.project-list .all-projects-search .bi-search{
    font-size: .85rem;
}
.project-list .all-projects-controls{
    flex-wrap: nowrap;
    margin-bottom: 0;
    font-size: .8rem;
}
/* Pushed to the far end of the sort row, so the controls and the count each keep
   their own side. */
.project-list-range{
    margin-left: auto;
    color: var(--project-meta);
    white-space: nowrap;
}
.project-list .project-row{
    padding: .75rem .4rem;
}
.project-list .project-row-year{
    font-size: 1.25rem;
}
.project-list .project-row-year.is-undated{
    font-size: .8rem;
}
.project-list .project-row-title{
    font-size: .95rem;
}
.project-list .project-row-meta{
    font-size: .78rem;
}
.project-list .all-projects-empty{
    padding: 1.5rem .4rem;
    font-size: .85rem;
}
@media (max-width: 1200px) {
    .project-list:not(.canvas) .project-row{
        flex-direction: column;
        gap: .35rem;
    }
    .project-list:not(.canvas) .project-row-year{
        flex: 0 0 auto;
    }
}

/* ---- pagination */

.project-list-footer{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    padding-top: .6rem;
    font-size: .8rem;
    color: var(--project-meta);
}
/* Bootstrap's pagination is a bordered strip; here it has to read as part of the
   list, so the boxes come off and only the current page keeps a fill. */
.project-list-footer .pagination{
    margin: 0;
    gap: .15rem;
}
.project-list-footer .page-link{
    min-width: 1.9rem;
    padding: .15rem .5rem;
    color: var(--primary-color);
    text-align: center;
    background: transparent;
    border: 0;
    border-radius: .4rem;
    transition: background-color var(--dur-fast) var(--ease-standard),
                color var(--dur-fast) var(--ease-standard);
}
.project-list-footer .page-link:hover{
    background-color: #f0f4ff;
}
.project-list-footer .page-item.active .page-link{
    color: #fff;
    background-color: var(--primary-color);
}
.project-list-footer .page-item.disabled .page-link{
    color: var(--project-year);
    background: transparent;
}

.full-page{
    padding-left: 0px !important;
}
.filter{
    text-decoration: none;
}
.filter.active{
    text-decoration: underline;
}

.filter-list > .input-group label{
    font-weight: 700;
}
.filter-list > .input-group select{
  max-width: 20rem;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}
.filter-list > .input-group label, .filter-list > .input-group select{
    color: var(--primary-color);
    border: 0;
    border-radius: .8rem;
}
.map-container {
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    z-index: 500;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    pointer-events: none;
    margin-bottom: 1rem;
}
/* The outer .leaflet-marker-icon carries Leaflet's positioning transform; this
   inner div is free to use transform of its own. */
@keyframes marker-in {
    from {
        opacity: 0;
        transform: scale(.6);
    }
}
.custom-circle-marker {
    background-color: var(--primary-color);
    color: white;
    border-radius: 50%;
    text-align: center;
    line-height: 30px;
    font-weight: bold;
    font-size: 15px;
    box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
    animation: marker-in var(--dur-slow) var(--ease-out) both;
    transition: transform var(--dur-fast) var(--ease-out),
                box-shadow var(--dur-fast) var(--ease-out);
}
.custom-circle-marker:hover {
    transform: scale(1.12);
    box-shadow: 0 0 6px rgba(0, 0, 0, 0.45);
}

/* ---- the 970px switch, part two

   Deliberately at the foot of the file rather than in the main (max-width: 970px) block
   near the top. Every rule here overrides a base rule declared further down than that
   block — .project-sheet, .table-tool, .map-container, .filter-container — and a media
   query carries no extra specificity, so from up there each of these would lose the tie on
   source order and do nothing at all. */
@media (max-width: 970px) {
    /* Three stacked dropdowns took the top third of a phone screen. Here they are a
       popover behind one button, in the strip that is already chrome.

       All four custom properties are written by map_filters.js off the navbar hamburger's
       own rect; the fallbacks are what the first paint uses, and are only right below
       767px, where the nav drops its percentage padding. */
    .filter-toggle{
        display: inline-flex;
        align-items: center;
        position: fixed;
        top: var(--filter-top, .9rem);
        right: var(--filter-right, 4rem);
        /* Above the sheet (600) — the panel hangs over it at the full stop — and below the
           navbar, for the stacking-context reason spelled out on .project-sheet. The button
           sits beside the hamburger, so being painted over the navbar menu would be the
           most visible version of that bug. */
        z-index: 700;
    }
    .filter-container{
        position: fixed;
        top: var(--filter-panel-top, 4rem);
        /* Hung from the hamburger's own gutter rather than from the button, so its edge
           lines up with the chrome instead of floating a button's width inside it. */
        right: var(--filter-gutter, .9rem);
        left: auto;
        margin: 0;
        z-index: 700;
        /* The 1230px rule right-aligns these; inside a panel they fill it instead. */
        align-items: stretch;
        gap: .5rem;
        width: max-content;
        min-width: 15rem;
        max-width: min(80vw, 22rem);
        /* A landscape phone has room for about one of these rows, so the panel scrolls
           rather than running off the bottom of the screen. */
        max-height: calc(var(--viewport-height) - var(--filter-panel-top, 4rem) - 1rem);
        overflow-y: auto;
        padding: .75rem;
        background-color: #fff;
        border-radius: 1rem;
        box-shadow: 0 4px 16px rgba(19, 80, 164, .18);
        /* The base rule leaves this click-through so the empty band over the map does not
           swallow taps; here it is a real surface. */
        pointer-events: auto;
        /* The same reveal the navbar's own dropdowns use. motion.css already zeroes every
           transition under prefers-reduced-motion, so there is nothing to repeat here. */
        opacity: 0;
        visibility: hidden;
        transform: translateY(-6px);
        transition: opacity var(--dur-base) var(--ease-standard),
                    transform var(--dur-base) var(--ease-out),
                    visibility var(--dur-base) linear;
    }
    .filter-container.is-open{
        opacity: 1;
        visibility: visible;
        transform: none;
    }
    .filter-container .filter-list{
        width: 100%;
    }
    /* The panel spaces its rows with gap; the margin would double it. */
    .filter-container .input-group{
        margin-bottom: 0;
    }
    /* The sheet is the project list at this width. */
    .project-sheet{
        display: flex;
    }
    /* The peek strip says "Project List" and opens on a tap, which is what the button was
       for; leaving it would only put a second control on top of the sheet. */
    .table-tool{
        display: none;
    }
    /* Both used to sit on the bottom edge the sheet now occupies. */
    .map-container{
        bottom: var(--sheet-peek);
    }
    .leaflet-bottom{
        bottom: var(--sheet-peek);
    }
}
