/* ── MOBILE ────────────────────────────────────────────────────────────
   One place for everything the phone needs and the desktop must not see.

   Every rule in this file lives inside a max-width media query, so the
   desktop layout cannot be touched from here by accident. It loads last,
   after every other stylesheet, so it wins on specificity ties without
   needing !important for ordinary overrides.

   The rules are grouped by what they fix, and each group says what was
   wrong — a phone bug is rarely obvious from the selector alone.

   Breakpoints, and only these three:
     900px — the hamburger appears; the phone/tablet layout starts here.
     640px — one column; sheets replace panels.
     380px — the smallest phones still in use.
────────────────────────────────────────────────────────────────────── */

/* ══ 1. FOUNDATIONS ══════════════════════════════════════════════════ */

@media (max-width: 900px) {

  /* ── The iOS zoom ──
     Safari zooms the whole page in when you focus a field whose text is
     under 16px, and it never zooms back out. Every form on RESIDE was 14 or
     15px, so tapping any field — sign in, post a listing, the island
     search inside a dropdown — threw the layout sideways and left the
     renter pinch-zooming their way back. 16px is the entire fix; nothing
     else about the field changes. */
  .form-input,
  .form-select,
  .form-textarea,
  .kd-search input,
  .pr-val-input,
  input[type="text"],
  input[type="email"],
  input[type="tel"],
  input[type="url"],
  input[type="number"],
  input[type="search"],
  input[type="password"],
  input[type="date"],
  textarea,
  select {
    font-size: 16px;
  }

  /* A tap that lands three pixels off should still land. Anything the
     finger is meant to hit gets a real target; where the control has to
     stay small for the bar's sake, the target grows by padding and the
     drawn box stays the size it was. */
  .theme-toggle,
  .nav-right .theme-toggle,
  .nav-hamburger {
    min-width: 44px;
    min-height: 44px;
    height: 44px;
  }
  /* The bars have to be centred in the box, not stacked at the top of it.
     .nav-hamburger is a column flex, so giving it a height without saying
     where its contents go left the three lines resting against the top
     edge — which put the menu icon eight pixels above the theme toggle and
     the mark beside it, and the whole bar read as crooked. */
  .nav-hamburger {
    padding: 0;
    gap: 5px;
    justify-content: center;
    align-items: center;
  }

  /* The save disc on a card and the social marks in the footer are drawn
     small on purpose. Growing them would change the design, so the tap
     area is grown around them instead — an invisible box on the pseudo
     element, which the drawing never sees. Same trick the photo-thumb
     remove button already uses (css/pages.css). */
  /* .card-fav / .pcard-fav are already absolutely positioned, so they are
     their own containing block; only the footer marks need one. */
  .footer-socials a { position: relative; }
  .card-fav::after,
  .pcard-fav::after { content: ''; position: absolute; inset: -5px; }
  .footer-socials a::after { content: ''; position: absolute; inset: -5px -3px; }
  .pw-toggle::after { content: ''; position: absolute; inset: -9px; }
  .pr-clear { min-height: 40px; padding: 8px 10px; }

  /* A link inside a sentence cannot be 44px tall without pushing the
     sentence apart — but vertical padding on an inline box is painted and
     hit outside the line without changing the line's height at all, which
     is exactly the target this needs and none of the layout it doesn't. */
  .auth-link,
  .kauth-forgot,
  .kauth-foot a,
  .form-hint a,
  .report-link,
  .legal p a,
  .legal li a,
  .sup-block p a { padding-block: 9px; }

  /* Leaflet's own +/- are 30px squares out of the box. Its stylesheet is
     loaded from a CDN after this file and says so at `.leaflet-touch
     .leaflet-bar a`, so matching that selector loses the tie on order —
     the touch class sits on the container itself, which is one class more
     to name and one more than Leaflet has. */
  .leaflet-container.leaflet-touch .leaflet-bar a,
  .leaflet-container .leaflet-bar a {
    width: 40px; height: 40px; line-height: 40px;
  }

  /* A secondary button is still a button somebody has to hit. */
  .btn-sm,
  .adm-btn { min-height: 42px; }

  /* Momentum and containment on every sideways rail, so a horizontal
     flick never becomes a vertical one halfway through — and never hands
     the gesture on to the page behind it. */
  .filter-bar-inner,
  .nd-adopted,
  .mp-rail,
  .gallery-thumbs,
  .lb-thumbs {
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
}

/* ── Stuck hover ──
   A touch screen has no pointer to leave, so :hover latches onto the last
   thing tapped and stays there — a card left lifted four pixels off the
   grid, a photo left zoomed in. Those states are decoration, so on a
   device with no hover they simply do not exist. */
@media (hover: none) {
  .listing-card:hover { transform: none; border-color: var(--hairline); }
  .listing-card:hover .card-img img,
  .listing-card:hover .card-img-placeholder { transform: none; }
  .card-fav:hover { transform: none; background: rgba(13,11,11,0.62); }
  .mp-prev:hover .mp-prev-img img { transform: none; }
  .gallery-cell:hover img { transform: none; }
  .kd-opt:hover { background: transparent; }
  .kd-opt.kd-selected:hover { background: rgba(126,123,120,0.22); }

  /* Pressing still has to answer. A tap that changes nothing on screen
     reads as a tap that missed. */
  .listing-card:active { border-color: var(--bronze); }
  .kd-opt:active { background: rgba(126,123,120,0.16); }
  .nav-mobile-menu a:active { background: rgba(126,123,120,0.16); }
}

/* ══ 2. THE HEADER AND THE MENU ══════════════════════════════════════ */

@media (max-width: 900px) {

  /* Room is the scarce thing in a 390px bar, so the gutters give some of
     it back to whatever is between them. */
  .navbar { padding: 0 16px; }

  /* ── The menu ──
     It used to be a dropdown: a panel hanging under the navbar, as tall
     as its own contents, with the page still showing above it (through a
     navbar that has no background of its own) and below it. Open, it read
     as a rendering fault rather than as a menu.

     It is now the screen. It starts at the top edge and the header's
     height is padding, so the mark, the theme toggle and the close cross
     stay exactly where they were and the bar never appears to change —
     but everything is the menu now, and what shows through the navbar's
     transparency is the menu, not the listings.

     Kept in the layout rather than display:none'd, so it can be seen to
     arrive instead of appearing. */
  .nav-mobile-menu {
    display: flex !important;
    top: 0; bottom: 0; left: 0; right: 0;
    height: auto;
    padding: calc(var(--nav-h) + 14px) 16px calc(20px + env(safe-area-inset-bottom, 0px));
    border-bottom: none;
    /* The blur was over a page that is no longer visible behind it. */
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    overflow-y: auto;
    overscroll-behavior: contain;
    gap: 0;
    z-index: 480;               /* under the navbar: the cross stays on top */
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(-10px);
    transition: opacity 0.24s var(--ease),
                transform 0.32s var(--expo-out),
                visibility 0.32s;
  }
  .nav-mobile-menu.open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
  }

  /* Fully opaque, in both themes. The panel used to be 98% over a page it
     only partly covered, where the 2% read as depth; covering the whole
     screen it reads as a listing photo showing through the menu. Doubled
     class name only to reach past the theme rule in variables.css, which
     is the one that set the 98%. */
  .nav-mobile-menu.nav-mobile-menu { background: var(--bg); }

  /* Full-width rows at a thumb's height, one per line. */
  .nav-mobile-menu a {
    display: flex;
    align-items: center;
    min-height: 48px;
    padding: 4px 12px;
    font-size: 16px;
    border-radius: 2px;
  }
  .nav-mobile-menu .nav-mobile-divider { margin: 14px 0 0; }

  /* The account row sits at the foot of the screen rather than directly
     under the last link — it is a different kind of thing, and the gap
     says so without a second rule. */
  .nav-mobile-bottom {
    margin-top: auto;
    padding-top: 18px;
    gap: 12px;
  }
  .nav-mobile-bottom .btn,
  .nav-mobile-bottom .btn-sm {
    min-height: 46px;
    font-size: 15px;
  }
  .nav-mobile-bottom.authed .nmb-user { padding: 2px 4px 8px; }

  /* While the menu is up, nothing else floats over it. */
  html.reside-menu-open .mp-fab,
  html.reside-menu-open .mobile-cta,
  html.reside-menu-open .si-rail,
  html.reside-menu-open #scroll-progress {
    opacity: 0;
    pointer-events: none;
  }

  /* Signed in, the avatar in the bar is a second account control beside
     the one already inside the menu. One of them is enough, and the menu
     is the one with room for a name. */
  .nav-right .nav-user-menu { display: none; }
}

/* ══ 3. THE FILTER BAR ═══════════════════════════════════════════════ */

@media (max-width: 900px) {

  /* ── The 30px filter bar ──
     `max-width: min(1240px, calc(100vw - 360px))` is the width the navbar
     gives this row on a laptop, and on a 390px phone it resolves to 30px:
     the whole filter row became a 30px window, centred, onto 750px of
     controls. That is the "Isla" sliver — an island field cropped to four
     letters with no way to reach any of the others.

     On a phone the row takes the full width and scrolls sideways, which
     is what it was always meant to do here. The gutter moves from the bar
     onto the row itself, so the first control starts on the page's margin
     and the last one can still scroll clear of the edge.

     Scoped through .filter-bar on purpose: the same row travels into the
     navbar (js/search-dock.js), and there it is a child of .nav-dock and
     must keep the navbar's spacing, not the page's. */
  .filter-bar { padding-left: 0; padding-right: 0; }
  .filter-bar .filter-bar-inner {
    max-width: none;
    width: auto;
    margin: 0;
    justify-content: flex-start;
    gap: 10px;
    padding: 2px 18px;
    scroll-padding-inline: 18px;
  }
  /* The chips under the row keep the gutter the bar just gave up. */
  .filter-bar .active-filters { padding: 0 18px; margin-top: 10px; }

  /* Every control in the row is a thumb target. */
  .filter-bar-inner .kd-trigger,
  .filter-bar-inner .filter-select,
  .filter-bar-inner .filter-toggle,
  .filter-bar-inner .sort-select,
  .filter-bar-inner .pr-btn,
  .filter-bar-inner .mp-trigger {
    height: 44px;
    min-height: 44px;
    font-size: 13.5px;
    padding-inline: 14px;
  }
  .afchip { min-height: 34px; padding: 6px 12px; }

  /* Docked in the navbar the row is the widest thing in the bar, so it
     takes every pixel the mark and the menu are not using. */
  .nav-dock { margin: 0 8px; }
  .nd-adopted { gap: 8px; }
}

/* ══ 4. THE HERO SEARCH ══════════════════════════════════════════════ */

@media (max-width: 900px) {
  /* Three stacked fields and a button, each one a full-width row. The
     field is sized by the 44px trigger inside it — a min-height on top of
     that only made the pill taller than the page it sits on. */
  .hs-field .kd-trigger { font-size: 15px; }
  .hs-go { min-height: 46px; }
}

/* ══ 5. DROPDOWNS AND THE BUDGET PANEL ═══════════════════════════════ */

@media (max-width: 900px) {

  /* ── The panel nobody can see ──
     A closed .kd-list / .pr-panel is invisible but still absolutely
     positioned and still 230–366px wide, which means it is still part of
     its scroller's scrollable area. Inside the RESIDE Watch modal — 360px
     wide, with a 360px budget panel in it — that gave the modal 17px of
     horizontal scroll it should never have had, so the whole dialog slid
     sideways and cut its own headings in half the moment a field was
     tapped and the browser scrolled to "reveal" it.

     Fixed takes it out of every ancestor's scroll area without taking it
     out of the layout, so it can still be measured and animated. Where it
     lands while closed does not matter: it is transparent and inert until
     js/popover.js places it. */
  .kd-list,
  .pr-panel { position: fixed; }

  /* js/popover.js already pins these to the viewport and caps their
     height. What it cannot decide is how big a row has to be before it
     can be tapped reliably — that is here. */
  .kd-opt {
    display: flex;
    align-items: center;
    min-height: 46px;
    padding: 13px 14px;
    font-size: 15px;
  }
  .kd-group { padding: 14px 14px 6px; }
  .kd-list { padding: 6px; min-width: 200px; }
  .kd-big .kd-list { min-width: 250px; }
  .kd-search { padding: 10px; }
  .kd-search input { padding: 11px 12px; }

  /* The budget panel is the one dropdown with controls inside it, so it
     gets the room to be operated. */
  .pr-panel { padding: 22px 18px 20px; }
  .pr-vals { gap: 8px; margin-bottom: 22px; }
  .pr-val-box { padding: 12px 13px; }
  .pr-slider-wrap { height: 52px; }
  /* A 22px handle on glass is a handle you miss. */
  .pr-range::-webkit-slider-thumb { width: 26px; height: 26px; }
  .pr-range::-moz-range-thumb { width: 24px; height: 24px; }
  .pr-presets button { min-height: 38px; padding: 8px 13px; }
  .pr-clear { min-height: 40px; }
}

/* ══ 6. MAP PEEK — THE PHONE SHEET ═══════════════════════════════════ */

@media (max-width: 900px) {

  /* ── The head ──
     Title and note shared one baseline, which is right on a drawer 480px
     wide and wrong on a phone: both wrapped to two lines and interleaved,
     so "Where these homes are" and "Showing 2 of 3 homes on the map" read
     as one broken paragraph with a cross in it. Stacked, they are a title
     and its note again. */
  .mp-sheet .mp-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
    gap: 2px 12px;
    padding: 20px 16px 12px;
  }
  .mp-sheet .mp-title { grid-column: 1; grid-row: 1; font-size: 18px; }
  .mp-sheet .mp-note  { grid-column: 1; grid-row: 2; font-size: 12px; line-height: 1.45; }
  .mp-sheet .mp-close {
    grid-column: 2; grid-row: 1 / span 2;
    align-self: center;
    width: 44px; height: 44px;
  }

  /* ── "N homes are outside the view" ──
     It is pinned to the bottom of the map's container, and on the sheet
     that container also holds the card rail — so the chip sat on top of
     the first card instead of on the map. --mp-rail-h is published by
     js/map-peek.js and is exactly how much of that bottom belongs to the
     rail. */
  .mp-sheet .mp-all {
    left: 12px; right: auto;
    bottom: calc(var(--mp-rail-h, 0px) + 12px);
    max-width: calc(100% - 24px);
    height: auto; min-height: 38px;
    padding: 8px 13px;
    text-align: left;
  }
  .mp-sheet .mp-all .mp-all-n { white-space: normal; }

  /* "Show homes in this area" clears the head and stays clear of the zoom
     controls on the right. */
  .mp-sheet .mp-area {
    top: 12px;
    height: auto; min-height: 40px;
    padding: 9px 16px;
    max-width: calc(100% - 96px);
  }

  /* The rail is the phone's marker preview, so it gets the width to be
     one. */
  .mp-sheet .mp-rail {
    gap: 8px;
    padding: 10px 12px calc(12px + env(safe-area-inset-bottom, 0px));
  }
  .mp-rcard { width: min(260px, 76vw); padding: 9px; }
  .mp-rcard-img { flex-basis: 66px; height: 66px; }

  /* The floating trigger clears the home indicator, and never sits under
     the listing page's contact bar. */
  .mp-fab {
    bottom: calc(16px + var(--mcta-h, 0px) + env(safe-area-inset-bottom, 0px));
    height: 46px;
    padding: 0 18px;
  }

  /* The empty state is a sentence, not a page. */
  .mp-empty { padding: 28px 24px; }
  .mp-empty-title { font-size: 18px; }
}

/* ══ 7. LISTING DETAIL ═══════════════════════════════════════════════ */

@media (max-width: 900px) {
  /* The contact bar is the one thing on this page that must never be
     covered, and it has to clear the phone's own home indicator. */
  .mobile-cta { padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }

  /* Everything the bar is pinned over has to end above it. --mcta-h is set
     by listing-detail.html once the bar has a height, and is undefined
     everywhere else — so this is exactly 0 on every other page. */
  .detail-layout { padding-bottom: calc(28px + var(--mcta-h, 0px)); }
  .site-footer { margin-bottom: var(--mcta-h, 0px); }

  /* The lightbox on a phone: the photo takes the screen, and the controls
     sit on its edges rather than 40px inside them. */
  .lightbox {
    padding: 16px 12px calc(16px + env(safe-area-inset-bottom, 0px));
    gap: 10px;
  }
  .lightbox > img { max-width: 100vw; max-height: 62vh; }
  .lb-close { top: calc(12px + env(safe-area-inset-top, 0px)); right: 12px; }
  .lb-close, .lb-nav { width: 44px; height: 44px; }
  .lb-prev { left: 8px; }
  .lb-next { right: 8px; }

  .gallery-thumbs, .lb-thumbs { scroll-padding-inline: 8px; }
}

/* ══ 8. FORMS ════════════════════════════════════════════════════════ */

@media (max-width: 900px) {
  /* ── The pricing note ──
     `margin-top: -22px` was pulling this line up into the box above it:
     against that box's own 18px bottom margin it collapsed to -4px, so
     the sentence started four pixels ABOVE the border it was meant to sit
     under and touched it the whole way across. It is a note about the box
     above, so it stays close — but under it. */
  .price-manual-note { margin: 2px 0 28px; }

  /* Deposit and advance: the label takes its own line and the amounts sit
     under it. What was missing was room to breathe once the row became
     three stacked things instead of one. */
  .pay-row { padding: 14px 0 16px; }
  .pay-row-note { margin-top: 5px; }
  .pay-edit { min-height: 40px; margin-top: 2px; }

  .form-textarea { min-height: 132px; }
}

/* ══ 9. OVERLAYS ═════════════════════════════════════════════════════ */

@media (max-width: 900px) {
  /* 100vh on a phone is the viewport with the address bar gone — which is
     not the viewport anyone is looking at, so a panel capped at it runs
     off the bottom until you scroll. dvh is the height that is actually
     there; the vh line stays first as the fallback. */
  .kw-modal {
    max-height: calc(100vh - 40px);
    max-height: calc(100dvh - 40px);
    border-radius: 3px;
    /* Reaching the end of this list must not hand the gesture on to the
       page behind it — the page is held, but iOS still rubber-bands it. */
    overscroll-behavior: contain;
  }
  .kw-overlay {
    align-items: flex-end;
    padding: 16px 14px calc(16px + env(safe-area-inset-bottom, 0px));
  }

  /* Every dismiss control on an overlay is a thumb target. The two that
     carry a drawn box keep the box they were designed with and grow only
     the area around it. */
  .lb-close,
  .mp-close,
  .report-close { min-width: 44px; min-height: 44px; }
  .kw-x, .kauth-x { position: absolute; }
  .kw-x::after,
  .kauth-x::after { content: ''; position: absolute; inset: -5px; }

  /* Breadcrumbs are links people aim at, not a caption. */
  .breadcrumb a { display: inline-flex; align-items: center; min-height: 36px; }
}

/* ══ 10. FOOTER ══════════════════════════════════════════════════════ */

@media (max-width: 900px) {
  /* Footer links were 16px tall and six apart — a column of near-misses.
     The text is unchanged; only the box around it grows. */
  .footer-col a,
  .footer-links a {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
  }
  .footer-links { gap: 20px; flex-wrap: wrap; }
}

/* ══ 11. NARROW PHONES ═══════════════════════════════════════════════ */

/* ══ 11. DROPDOWNS AS SHEETS ═════════════════════════════════════════
   Below 640px js/popover.js stops hanging panels off their control and
   rises them from the bottom edge instead. The class is applied there;
   the shape is here.

   The dim behind it is a shadow, not an element — see the note in
   popover.js. 100vmax guarantees it reaches the far corner of the screen
   in either orientation. */

@media (max-width: 640px) {
  .reside-sheet {
    border: 1px solid var(--hairline);
    border-bottom: none;
    border-radius: 4px 4px 0 0;
    box-shadow: 0 -14px 38px rgba(0, 0, 0, 0.34),
                0 0 0 100vmax rgba(0, 0, 0, 0.55);
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    z-index: 2000;
    /* Placement is measured, and a transform mid-transition would be
       measured with it. The panel fades in instead. */
    transform: none !important;
  }

  /* The grab mark. Not a control — the sheet is closed by tapping past it
     or by choosing something — but it is what says which edge this came
     from and which way it goes back. */
  .reside-sheet::before {
    content: '';
    position: sticky;
    top: 0;
    z-index: 3;
    display: block;
    width: 40px; height: 4px;
    margin: 0 auto 10px;
    border-radius: 100px;
    background: var(--hairline);
  }

  /* A list sheet is all rows, so it keeps its own small padding and lets
     the search box sit under the grab mark rather than over it. */
  .kd-list.reside-sheet { padding: 10px 8px; z-index: 2000; }
  .kd-list.reside-sheet .kd-search { top: 14px; margin: 0 -8px 4px; }
  .kd-list.reside-sheet .kd-group { padding-top: 16px; }

  /* The budget panel is a form, so it keeps a form's margins. */
  .pr-panel.reside-sheet { padding: 12px 20px 20px; }
  .pr-panel.reside-sheet .pr-header { padding-top: 2px; }
}

@media (max-width: 640px) {
  /* One thing per line, wherever a pair of controls was sharing one. */
  .nav-mobile-bottom:not(.authed) { flex-direction: column; }
  .nav-mobile-bottom:not(.authed) .btn { width: 100%; }

  /* "View All" beside a section heading is a link people aim at. */
  .link-all { display: inline-flex; align-items: center; min-height: 40px; }
}

@media (max-width: 380px) {
  .navbar { padding: 0 12px; }
  .filter-bar .filter-bar-inner { padding-inline: 14px; scroll-padding-inline: 14px; }
  .filter-bar .active-filters { padding: 0 14px; }
  .nav-mobile-menu { padding-left: 12px; padding-right: 12px; }
  .mp-rcard { width: 78vw; }
}
