:root {
  --navy: #0e1b3d;
  --blue: #1a56db;
  --gray-bg: #f5f6f8;
  --gray-text: #6b7280;
  --border: #e5e7eb;
}

* { box-sizing: border-box; }

/* Fixes a real reported bug (2026-08-29): mobile browsers (Safari/Chrome)
   let the page rubber-band-scroll past its own content, revealing blank
   space below the fixed bottom nav as if you'd scrolled "through" it. This
   isn't the footer itself misbehaving -- it's the page's own overscroll/
   bounce effect. `none` on both html and body is needed; body alone isn't
   always enough on iOS Safari specifically. */
html { overscroll-behavior: none; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--gray-bg);
  color: #111827;
  padding-bottom: 90px; /* space for bottom nav -- bumped 2026-08-21 alongside its taller height */
  overscroll-behavior: none;
}

.hidden { display: none !important; }

/* ---------- pull-to-refresh (2026-08-29) ---------- */
/* Sits fixed at the very top, translated fully off-screen by default;
   initPullToRefresh() in app.js drives its transform/text directly as the
   visitor drags, so the transition below only smooths the snap-back on
   release, not the live drag itself (which needs to track the finger
   exactly, no lag). z-index above everything, including the login gate
   (1000) -- a reload is meaningful even from the gate itself. */
.pull-refresh-indicator {
  position: fixed; top: 0; left: 0; right: 0; z-index: 1001;
  display: flex; align-items: center; justify-content: center;
  height: 50px; margin-top: -50px;
  background: var(--navy); color: #fff; font-size: 13px; font-weight: 600;
  transition: margin-top 0.2s ease;
}
.pull-refresh-indicator.dragging { transition: none; }

/* ---------- top bar (responsive masthead, added 2026-08-21) ---------- */
/* Wide screens: title bar + icon/label top tabs, matching the real Glide
   app's landscape layout. Narrow screens: collapses to a hamburger + the
   current tab name, opening a slide-out drawer -- matching Glide's portrait
   layout. Breakpoint chosen to roughly track phone-portrait vs. everything
   wider (tablet landscape and up), not tied to any specific device. */
.topbar {
  position: relative; /* anchors .admin-login-popover's absolute positioning */
  background: var(--navy);
  color: #fff;
  padding: 10px 16px;
}
.masthead-row { display: flex; align-items: center; gap: 12px; }
.masthead-title { font-size: 18px; font-weight: 800; margin: 0; flex: 1; }
.mobile-current-tab { display: none; flex: 1; text-align: center; font-size: 15px; font-weight: 800; letter-spacing: 0.5px; }
.hamburger-btn {
  display: none; background: none; border: none; color: #fff; font-size: 22px; padding: 4px 6px; cursor: pointer;
}
.admin-login-btn {
  /* Camouflaged, added 2026-08-29 per Aaron's direct request -- the
     unactivated icon is now the exact same color as the header background,
     so it's effectively invisible to a regular visitor who doesn't already
     know it's there. Still fully present/tappable, just not visually
     announcing itself. Turns solid green (.signed-in) once actually
     logged in, as a quiet confirmation only Aaron would recognize. */
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%; border: none; background: none;
  color: var(--navy); cursor: pointer; flex: 0 0 auto;
}
.admin-login-btn.signed-in { color: #7ee0a8; }
.admin-login-popover {
  position: absolute; top: 52px; right: 16px; z-index: 30;
  background: #fff; border: 1px solid var(--border); border-radius: 10px;
  padding: 10px; box-shadow: 0 6px 20px rgba(0,0,0,0.15);
}
.admin-logout-btn {
  display: block; width: 100%; margin-top: 8px; padding: 6px; font-size: 12px;
  background: none; border: 1px solid var(--border); border-radius: 8px; color: #6b7280; cursor: pointer;
}
.top-tabs { display: flex; gap: 6px; margin-top: 10px; }
.top-tabs .nav-btn {
  flex: 0 0 auto; flex-direction: row; gap: 6px; background: none; border: none; color: #9aa7c7;
  font-size: 13px; font-weight: 700; padding: 8px 12px; border-radius: 8px; cursor: pointer;
}
.top-tabs .nav-btn.active { color: #fff; background: rgba(255,255,255,0.12); }
.top-tabs .nav-icon { font-size: 15px; }

/* Drawer -- mobile only, reuses .nav-btn so the existing click handler
   (queries all .nav-btn elements) needs no extra JS wiring for tab-switching
   itself; only open/close behavior is new. */
.nav-drawer-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 40;
}
.nav-drawer {
  position: fixed; top: 0; left: 0; bottom: 0; width: 240px; background: var(--navy);
  z-index: 41; padding: 20px 12px; display: flex; flex-direction: column; gap: 4px;
  transform: translateX(0); transition: transform 0.2s ease;
}
.nav-drawer.hidden, .nav-drawer-backdrop.hidden { display: none; }
.nav-drawer .nav-btn {
  flex: 0 0 auto; flex-direction: row; justify-content: flex-start; gap: 10px; background: none; border: none;
  color: #cbd5e1; font-size: 14px; font-weight: 700; padding: 12px 10px; border-radius: 8px; cursor: pointer; width: 100%;
}
.nav-drawer .nav-btn.active { color: #fff; background: rgba(255,255,255,0.12); }
.nav-drawer .nav-icon { font-size: 16px; }

/* Profile bar -- moved out of the navy header into its own light-background
   section (matches both reference screenshots: profile card sits below the
   masthead, not inside it). */
.profile-bar {
  background: #fff; border-bottom: 1px solid var(--border);
  padding: 10px 16px; display: flex; justify-content: space-between; align-items: center;
  max-width: 640px; margin: 0 auto; gap: 10px;
  /* Deliberately no flex-wrap -- per Aaron's 2026-08-21 reference screenshot,
     the icons stay pinned to the right of the name/tagline in the same row
     at every width (was wrapping onto its own line below on narrow screens,
     costing extra vertical height). */
}
.profile { display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1; }
/* min-width: 0 above is required -- without it, a flex child won't let its
   text content shrink/wrap and will instead push .profile-actions off to
   the side or force the row to overflow. */
.profile-text { min-width: 0; }
.avatar {
  width: 48px; height: 48px; border-radius: 8px; object-fit: cover; background: #333; flex: 0 0 auto;
  /* Square (soft-rounded), not circular -- per Aaron's explicit 2026-08-21
     request: a circular crop was cutting off the top of his head. */
}
.profile-text .name { font-size: 14px; color: var(--gray-text); }
.profile-text .tagline { font-size: 14px; font-weight: 600; color: #111827; line-height: 1.3; }
.profile-actions { display: flex; gap: 8px; flex: 0 0 auto; }
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 40px; padding: 0 14px; border-radius: 20px; border: none; cursor: pointer;
  background: #eef2ff; color: var(--blue); text-decoration: none; font-size: 14px; font-weight: 700;
  font-family: inherit; /* buttons don't inherit this by default like <a> tags do -- needed since Install (added 2026-08-29) is a <button>, not a link like Call/Text */
}
.icon-btn-icon { display: inline-flex; }
.icon-btn-outline {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%;
  background: #fff; color: #111827; border: 1px solid var(--border); font-size: 16px;
}
.count-badge {
  position: absolute; top: -4px; right: -4px; min-width: 16px; height: 16px; padding: 0 3px;
  border-radius: 8px; background: var(--blue); color: #fff; font-size: 10px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; line-height: 1;
}

@media (max-width: 700px) {
  .masthead-title, .top-tabs { display: none; }
  .mobile-current-tab { display: block; }
  .hamburger-btn { display: block; }
  /* icon-only circles on mobile, matching the portrait reference screenshot */
  .icon-btn { width: 40px; height: 40px; padding: 0; border-radius: 50%; }
  .icon-btn-label { display: none; }
}
@media (min-width: 701px) {
  .nav-drawer, .nav-drawer-backdrop { display: none !important; }
  /* Fixed 2026-08-22 (real bug, not just a design gap): the later,
     unconditional ".bottom-nav { display: flex }" base rule further down
     this file has equal specificity and was silently winning over this one
     whenever both conditions were true (i.e. always, on any wide/landscape
     screen) -- the footer was never actually being hidden here. !important
     added to match the pattern already used one line above for this exact
     reason. */
  .bottom-nav { display: none !important; }
}

/* ---------- main / tabs ---------- */
main { padding: 16px; max-width: 640px; margin: 0 auto; }
.page-title { font-size: 26px; font-weight: 800; margin: 8px 0 16px; }

/* ---------- rent-vs-own frame ---------- */
.rent-frame {
  background: #101a35; color: #fff; border-radius: 14px; padding: 20px; margin-bottom: 16px;
}
.rent-frame-headline { font-size: 16px; font-weight: 700; margin: 0 0 14px; }
.rent-frame-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 480px) { .rent-frame-cols { grid-template-columns: 1fr; } }
.rent-col-title { font-size: 13px; font-weight: 700; color: #93a3c9; text-transform: uppercase; margin-bottom: 8px; }
.own-col .rent-col-title { color: #7ee0a8; }
.rent-frame ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
.rent-frame li { font-size: 13px; line-height: 1.4; color: #d7deed; }
.own-col li { color: #eafff2; }

/* ---------- stats strip ---------- */
.stats-strip {
  display: flex; gap: 10px; overflow-x: auto; margin-bottom: 16px; padding-bottom: 2px;
}
.stat-pill {
  flex: 0 0 auto; background: #fff; border: 1px solid var(--border); border-radius: 10px;
  padding: 8px 14px; font-size: 12px; color: var(--gray-text); white-space: nowrap;
}
.stat-pill strong { display: block; font-size: 16px; color: #111827; }

/* ---------- search + filters ---------- */
.search-row { display: flex; gap: 8px; margin-bottom: 12px; }
.search-input-wrap { position: relative; flex: 1; }
.search-icon {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--gray-text);
  display: flex; pointer-events: none;
}
.search-row input[type="search"] {
  width: 100%; padding: 12px 14px 12px 36px; border-radius: 10px; border: 1px solid var(--border); background: #fff;
}
.link-pill {
  display: flex; align-items: center; width: 100%; text-align: left; background: #eef2ff; color: var(--blue);
  border: none; border-radius: 20px; padding: 10px 16px; margin-bottom: 16px; font-size: 14px; cursor: pointer;
}
.filter-panel {
  background: #fff; border: 1px solid var(--border); border-radius: 12px; padding: 16px; margin-bottom: 16px;
  display: flex; flex-direction: column; gap: 12px;
}
.filter-panel label { display: flex; flex-direction: column; font-size: 13px; color: var(--gray-text); gap: 4px; }
.filter-panel input, .filter-panel select { padding: 8px; border-radius: 8px; border: 1px solid var(--border); font-size: 14px; }
.filter-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.filter-actions .btn-primary, .filter-actions .btn-outline { flex: 1; min-width: 140px; }
.filter-panel .link-pill { margin-bottom: 0; justify-content: center; }

.area-filter { display: flex; flex-direction: column; gap: 6px; }
.area-filter-label { font-size: 13px; color: var(--gray-text); }
.area-checkboxes {
  display: flex; flex-wrap: wrap; gap: 6px; max-height: 160px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: 8px; padding: 8px;
}
/* .filter-panel label (a descendant selector, specificity 0,1,1) is more
   specific than the bare .area-checkbox class (0,1,0) and would otherwise
   override this back to column layout/13px gray text -- scope with
   .filter-panel to win instead (0,2,0). */
.filter-panel .area-checkbox {
  flex-direction: row; display: flex; align-items: center; gap: 5px; background: var(--gray-bg);
  border-radius: 14px; padding: 5px 10px; font-size: 12px; color: #111827; cursor: pointer;
}
.area-checkbox input { margin: 0; }

.freshness { font-size: 12px; color: var(--gray-text); margin-bottom: 8px; }

/* ---------- card grid ---------- */
.card-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
/* 4 cards per row in landscape, per Aaron's explicit request (2026-08-21).
   min-width guard avoids a landscape phone/small window rendering 4
   overly-cramped columns -- roughly the point where 4x~150px columns still
   have room to breathe. Widen the content container too, otherwise 4
   columns inside the portrait-oriented 640px max-width would be cramped
   regardless of how much real landscape width is available. */
@media (orientation: landscape) and (min-width: 640px) {
  .card-grid { grid-template-columns: repeat(4, 1fr); }
  main, .profile-bar { max-width: 900px; }
}
.card {
  position: relative; /* anchors .card-heart's absolute positioning, added 2026-08-29 */
  background: #fff; border-radius: 12px; overflow: hidden; border: 1px solid var(--border);
  cursor: pointer; display: flex; flex-direction: column;
  /* "jump from the page just a bit" -- a soft elevation shadow plus a slight
     lift on hover/tap, kept subtle rather than a heavy animation. */
  box-shadow: 0 2px 8px rgba(0,0,0,0.08);
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
/* ---------- favorite heart (2026-08-29) ---------- */
/* Positioning context for the heart + admin badges, added 2026-08-29 --
   scopes their absolute positioning to the photo itself (mirrors the
   existing .detail-photo-wrap below), not the whole .card (which also
   includes the price/beds text under the photo). */
.card-photo-wrap { position: relative; }
.card-heart, .detail-heart {
  position: absolute; top: 10px; right: 10px; z-index: 5;
  width: 34px; height: 34px; border-radius: 50%; border: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.9); color: #6b7280;
  box-shadow: 0 1px 4px rgba(0,0,0,0.2);
}
.card-heart svg, .detail-heart svg { fill: none; }
.card-heart.favorited, .detail-heart.favorited { color: #e0245e; }
.card-heart.favorited svg, .detail-heart.favorited svg { fill: currentColor; }
.detail-photo-wrap { position: relative; }
.card:hover, .card:active {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0,0,0,0.12);
}
.card img { width: 100%; aspect-ratio: 4/3; object-fit: cover; background: #ddd; }
.card-body { padding: 10px 12px 14px; }
.card-status { font-size: 12px; font-weight: 700; color: var(--blue); text-transform: uppercase; }
.card-status.sold { color: #6b7280; }
.card-status.pending { color: #b45309; }
.card-address { font-weight: 700; font-size: 14px; margin: 4px 0; }
.card-meta { font-size: 13px; color: var(--gray-text); }
.card-money { font-size: 13px; margin-top: 4px; }
.empty-state { text-align: center; color: var(--gray-text); padding: 40px 16px; }

/* ---------- detail view ---------- */
#view-detail .detail-photo { width: 100%; aspect-ratio: 16/10; object-fit: cover; border-radius: 0 0 12px 12px; background: #ddd; }
.detail-back {
  /* 2026-08-22, second pass: a translucent background (even at 0.6 opacity)
     still blended into some photos, per Aaron's follow-up report -- no
     opacity percentage can guarantee contrast against an arbitrary photo
     underneath it. Switched to a fully solid (opaque) background instead,
     which is contrast-independent of whatever's behind it -- plus a white
     ring so it also stands out against the site's own light body
     background if it's ever seen off the photo. */
  /* top: 0; left: 0; added 2026-08-29, real reported bug: "position:
     absolute" with margin but no inset (top/left/right/bottom) values
     falls back to the element's normal in-flow ("static") position --
     margin alone never creates a corner-floating effect. This button had
     been silently rendering in plain document flow instead of floating
     over the top-left of the photo, likely since whichever edit last
     touched this rule (its own history shows a background-color pass on
     2026-08-22, not a position change) -- undetected until Aaron reported
     the arrow "not appearing where it used to be." */
  position: absolute; top: 0; left: 0; margin: 10px; background: var(--navy); color: #fff; border: 2px solid #fff;
  border-radius: 50%; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.detail-body { padding: 16px; }
.detail-status { font-size: 24px; font-weight: 800; }
.detail-address { color: var(--gray-text); margin-bottom: 16px; }
.action-row { display: flex; gap: 10px; margin-bottom: 10px; }
.btn-primary, .btn-outline {
  flex: 1; text-align: center; padding: 12px; border-radius: 10px; font-weight: 700; text-decoration: none; font-size: 14px; cursor: pointer; border: none;
}
.btn-primary { background: var(--blue); color: #fff; }
.btn-outline { background: #fff; border: 1px solid var(--border); color: #111827; }
.btn-full { display: block; width: 100%; margin-bottom: 10px; }
.detail-field { display: flex; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid var(--border); font-size: 14px; }
/* overflow-wrap (not word-break: break-all) -- per Aaron's 2026-08-22
   request, prose like Additional Notes should wrap at word boundaries
   normally, not split mid-word. overflow-wrap: break-word still forces a
   break for a single unbreakable long string (e.g. the Photo Link URL)
   when there's truly no other way to avoid overflowing the container, so
   long URLs still don't spill out of their box either. */
.detail-field .value { text-align: right; overflow-wrap: break-word; max-width: 60%; }
.detail-field .value a { color: var(--blue); }

.admin-info-section {
  margin-top: 16px; padding: 12px; background: #fffbeb; border: 1px solid #fde68a; border-radius: 10px;
}
.admin-info-title { font-size: 12px; font-weight: 700; color: #92400e; text-transform: uppercase; margin-bottom: 6px; }
.admin-info-status { font-size: 13px; color: #92400e; }
.admin-info-section .detail-field { border-bottom-color: #fde68a; }

/* ---------- map ---------- */
/* Map, 2026-08-22: an inline accordion on the home page itself, not a
   separate page -- see the HTML comment above #map-accordion. Its own
   search bar (and .map-search-status) was removed the same day -- now
   redundant since the map mirrors the page's own filters. */
.map-accordion { margin-bottom: 16px; }
#map-canvas { width: 100%; height: 50vh; border-radius: 12px; background: #ddd; }

/* ---------- map marker popup (Google Maps InfoWindow content) ---------- */
/* This renders inside Google's own InfoWindow chrome, which strips most
   page-level CSS custom properties/box model assumptions -- kept simple and
   self-contained rather than reusing .card, since InfoWindow content has
   its own sizing quirks (no viewport units, limited width). */
/* Slimmed 2026-08-22 (was 220px/130px photo -- Aaron reported content
   getting cut off). Paired with an explicit maxWidth on the InfoWindow
   itself in app.js, since Google's InfoWindow chrome can clip/scroll
   content that doesn't fit its own auto-sized bounds otherwise. */
.map-popup { width: 168px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
.map-popup-photo { width: 100%; height: 96px; object-fit: cover; border-radius: 6px 6px 0 0; display: block; }
.map-popup-body { padding: 6px 2px 2px; }
.map-popup-status { font-size: 10px; font-weight: 700; color: #1a56db; text-transform: uppercase; }
.map-popup-status.sold { color: #6b7280; }
.map-popup-status.pending { color: #b45309; }
.map-popup-address { font-weight: 700; font-size: 12px; margin: 2px 0; color: #111827; line-height: 1.25; }
.map-popup-meta { font-size: 11px; color: #6b7280; }
.map-popup-money { font-size: 11px; color: #111827; margin-top: 2px; }
.map-popup-btn { width: 100%; margin-top: 6px; padding: 6px; font-size: 12px; }

/* ---------- static pages ---------- */
.static-page h1 { font-size: 22px; font-weight: 800; }
.static-page h2 { font-size: 16px; margin-top: 20px; }
.static-page p, .static-page li { color: var(--gray-text); font-size: 14px; line-height: 1.5; }

/* .rent-frame now also lives inside .static-page (moved to the Approved!
   tab 2026-08-21) -- ".static-page p/li" above is more specific than the
   bare ".rent-frame-headline"/".rent-frame li" rules and would otherwise
   silently override them (gray 14px text instead of the intended white/
   colored styling). These re-assert the rent-frame's own look wherever it's
   embedded. */
.static-page .rent-frame-headline { color: #fff; font-size: 16px; line-height: 1.3; }
.static-page .rent-frame li { color: #d7deed; font-size: 13px; line-height: 1.4; }
.static-page .own-col li { color: #eafff2; }

/* ---------- 5 steps ---------- */
/* overflow-x: auto REMOVED same day -- real reported bug: the pill-shaped
   buttons below were wide enough that all 5 didn't fit across a real
   iPhone screen, so the row silently became horizontally scrollable
   instead of showing every step at once, which Aaron explicitly didn't
   want ("I don't wanna have to scroll left and right"). Fixed at the
   actual cause, not by re-adding scroll affordance: each tab now takes an
   equal flex: 1 share of the full row width (see .step-tab below), so 5
   always fit edge-to-edge on any real screen width, nothing to scroll. */
.step-tabs { display: flex; gap: 6px; border-bottom: 1px solid var(--border); padding-bottom: 12px; margin-bottom: 16px; }
/* Rebuilt as real buttons 2026-08-29, per Aaron's direct request -- the
   old plain-text tabs (no background/border at all when inactive) didn't
   read as clickable buttons. Sizing revisited the same day (see above):
   flex: 1 makes each of the 5 take an equal share of the row instead of
   sizing to its own text, and padding/font-size/radius were all reduced
   from the first pass so "Step 1"-"Step 5" still read cleanly at the
   narrower width that results. */
.step-tab {
  flex: 1; background: #fff; border: 1px solid var(--border); border-radius: 10px;
  font-size: 12px; font-weight: 700; color: #111827;
  padding: 8px 2px; cursor: pointer; white-space: nowrap; text-align: center;
}
.step-tab.active { color: #fff; font-weight: 800; background: var(--blue); border-color: var(--blue); }
.step-actions { display: flex; gap: 10px; margin-top: 16px; }
/* Swipe-between-steps support, added 2026-08-29 per Aaron's direct
   request -- a light touch-feedback cue (brief opacity dip) so a real
   swipe gesture on the content area gives some visual response, distinct
   from a tab click which already has its own active-state feedback. */
.step-content { transition: opacity 0.15s ease; }
.step-content.swiping { opacity: 0.5; }

/* ---------- buyer form / card-grouped static pages ---------- */
.form-card { background: #fff; border-radius: 12px; padding: 20px; border: 1px solid var(--border); }
/* Get Started split into multiple stacked .form-cards 2026-08-29, per
   Aaron's direct request ("wall of text... more intimidating than it
   should [be]") -- gap between them, since .form-card itself has no
   margin (it was previously the one single outer box, nothing to space
   from). Same day, extended to Approved! (h2 sections) and How it Works
   (step content) -- reused wherever a .static-page groups its own content
   into cards, not just Get Started specifically anymore, hence the
   broader .static-page scope rather than #get-started-form alone. */
.static-page .form-card { margin-bottom: 16px; }
/* A heading as a card's own first child shouldn't ALSO carry
   .static-page h2's own margin-top:20px -- that's meant for a heading
   breaking up a page's flat flow, not one sitting inside a padded card
   right at its top edge. Covers both Get Started's own
   <h2 class="form-card-heading"> and Approved!'s plain <h2> sections. */
.form-card > h2:first-child { margin-top: 0; }
.form-card-heading { margin: 0 0 14px; font-size: 15px; font-weight: 800; color: #111827; }
/* Sits right under the ID label, above the actual file input -- the exact
   wording the brief custom upload BUTTON used before it was reverted back
   to the native file input, per Aaron's request to keep that phrase
   visible somewhere even without the button itself. */
.get-started-id-hint { margin: 4px 0 0; font-size: 13px; font-weight: 700; color: var(--blue); }

/* Install banner, rebuilt 2026-08-29 -- replaces the old small icon button
   that lived in .profile-bar. Sits full-width right below the header. */
.install-banner {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  background: var(--navy); color: #fff;
}
.install-banner-icon { font-size: 20px; flex: 0 0 auto; }
.install-banner-text { flex: 1; font-size: 13px; font-weight: 600; line-height: 1.3; }
.install-banner-btn { padding: 8px 16px; font-size: 13px; border-radius: 8px; flex: 0 0 auto; }
.install-banner-dismiss {
  background: none; border: none; color: #fff; opacity: 0.7; font-size: 16px;
  cursor: pointer; padding: 4px 6px; flex: 0 0 auto; line-height: 1;
}
.install-banner-dismiss:hover { opacity: 1; }

/* Get Started -- Call/Text buttons + "Your Appointments" section, added
   2026-08-29. */
.get-started-contact-buttons { display: flex; gap: 10px; margin-top: 14px; }
.get-started-contact-buttons .btn-outline { flex: 1; text-align: center; }

/* Holds full buildListingCard() cards now (redesigned 2026-08-29 -- see
   that comment in app.js), one per active appointment, stacked -- .card's
   own flex-column default stretch already gives each card full width of
   this wrapper without needing an explicit width rule here. */
/* Accordion wrapper, added 2026-08-29 per Aaron's direct request -- the
   card list starts collapsed behind a "See your N booked viewings" toggle
   rather than always showing, so this section doesn't push the actual
   booking form down the page for a visitor just glancing at Get Started. */
.appointments-accordion { margin-bottom: 18px; }
.appointments-accordion-toggle {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-radius: 10px; border: 1px solid var(--border);
  background: #eef2ff; color: var(--navy); font-weight: 700; font-size: 14px; cursor: pointer;
}
.appointments-accordion-chevron { transition: transform 0.15s ease; }
.appointments-accordion-toggle.expanded .appointments-accordion-chevron { transform: rotate(180deg); }
/* Same grid sizing as the Homes/Favorites card-grid, added 2026-08-29 per
   Aaron's direct request ("same width as on the Homes page") -- was a
   full-width flex-column stack of full-size cards before. Real reported
   bug, same day: only the portrait 2-column part of that match was ever
   applied -- the landscape 4-column breakpoint below was missing, so this
   stayed 2-up in landscape while .card-grid switched to 4. Same media
   query as .card-grid now covers both. */
.appointments-banner-wrap { margin-top: 10px; display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (orientation: landscape) and (min-width: 640px) {
  .appointments-banner-wrap { grid-template-columns: repeat(4, 1fr); }
}

/* Appointment banner, redesigned 2026-08-29 from a standalone bordered box
   into a section embedded INSIDE a card (see buildListingCard) -- no
   longer its own border/radius (that would look like a card-within-a-
   card), just a light-tinted strip with a top divider separating it from
   the card's own price/beds line above it. */
.appointment-banner {
  background: #f0f3fb; border-top: 1px solid var(--border);
  padding: 10px 12px 12px; display: flex; flex-direction: column; gap: 8px;
}
.appointment-banner .appointment-date { font-weight: 600; font-size: 13px; color: #111827; }
.appointment-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.appointment-actions .btn-small {
  padding: 8px 12px; font-size: 12px; border-radius: 8px; border: 1px solid var(--border);
  background: #fff; color: #111827; cursor: pointer;
}
.appointment-actions .btn-small.btn-danger { color: #c0293c; border-color: #f0c3ca; }
.appt-date-picker { padding: 6px 8px; border-radius: 8px; border: 1px solid var(--border); font-size: 13px; }

/* Admin-only badges, rearranged twice now: first (2026-08-29) to favorites
   under the heart + appointments at the card's own bottom-right corner;
   then (same day, real reported bug -- appointments was anchoring to the
   bottom of the WHOLE card, including the price/beds text below the
   photo, not the photo itself) both moved to be children of
   .card-photo-wrap (below) so they anchor to the photo specifically, and
   restacked so appointments (blue) sits directly below favorites (red),
   both at the photo's bottom-right corner. Two independent counts, each
   rendered only when its own count is > 0 -- no longer need a .stacked
   variant now that neither shares a slot with the other. */
.admin-appointment-badge, .admin-favorite-badge {
  position: absolute; right: 10px; z-index: 5;
  min-width: 22px; height: 22px; padding: 0 6px; border-radius: 11px;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; color: #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,0.2);
}
/* bottom: 40px = appointment badge's own bottom (10px) + its height (22px)
   + an 8px gap -- stacks favorites directly above appointments. */
.admin-favorite-badge { bottom: 40px; background: #c0293c; }
.admin-appointment-badge { bottom: 10px; background: var(--blue); }

/* Detail-page "Scheduled Appointments" / "Favorited By" lists, added
   2026-08-29 -- same visual language as the existing admin-info-* blocks
   this sits alongside. */
.admin-activity-row {
  padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 13px;
}
.admin-activity-row:last-child { border-bottom: none; }
.admin-activity-contact { color: var(--gray-text); margin-top: 2px; }

/* Get Started property autocomplete, added 2026-08-29 -- replaces a plain
   <select> that listed every Available property in one long native
   dropdown. */
.autocomplete-wrap { position: relative; }
.autocomplete-list {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 10;
  margin: 4px 0 0; padding: 4px; list-style: none;
  background: #fff; border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 6px 20px rgba(0,0,0,0.12);
  max-height: 220px; overflow-y: auto;
}
.autocomplete-list li {
  padding: 10px 12px; border-radius: 6px; cursor: pointer; font-size: 14px;
}
.autocomplete-list li:hover, .autocomplete-list li.active { background: #f0f3fb; }
.autocomplete-list li.no-results { color: var(--gray-text); cursor: default; }
.autocomplete-list li.no-results:hover { background: none; }
.get-started-policy { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border); font-size: 13px; color: var(--gray-text); line-height: 1.5; }
/* Sits between the date picker and Full Name -- added 2026-08-29, split
   out of .get-started-policy above (see that rule's comment). No top
   border/large margin here, unlike .get-started-policy -- this is a note
   between two form fields, not a section break after the whole form. */
.get-started-hours-note { margin: 6px 0 0; font-size: 13px; color: var(--gray-text); line-height: 1.5; }
/* Sits inside the ID label, below the file field itself -- added
   2026-08-29, same shape as .get-started-hours-note above (this text
   moved twice the same week: originally above the page header, then
   above the ID field, now below it, per Aaron's own iterative requests). */
.get-started-id-note { margin: 6px 0 0; font-size: 13px; color: var(--gray-text); line-height: 1.5; }
#get-started-form label { display: block; margin: 16px 0 4px; font-weight: 600; font-size: 14px; }
.required { font-weight: 400; color: var(--gray-text); font-size: 12px; margin-left: 6px; }
#get-started-form input, #get-started-form select { width: 100%; padding: 10px; border-radius: 8px; border: 1px solid var(--border); margin-top: 4px; font-family: inherit; font-size: 14px; background: #fff; }
.full-width { width: 100%; margin-top: 20px; }
.form-status { margin-top: 12px; font-size: 14px; }
.get-started-id-status { margin: 6px 0 0; font-size: 13px; font-weight: 600; color: #1a8a4a; }

/* ---------- bottom popover (shared shape, install app 2026-08-29 +
   booking confirmation 2026-08-29) ---------- */
/* Renamed from .install-ios-popover to .bottom-popover the same day it was
   reused for the "Booked!" confirmation, since a class literally named
   "install" on an unrelated booking-confirmation popup would mislead the
   next person reading this file -- both elements share the exact same
   fixed-bottom-banner shape/style, so one class earns its keep here. */
.bottom-popover {
  position: fixed; left: 16px; right: 16px; bottom: 16px; z-index: 900;
  background: var(--navy); color: #fff; border-radius: 12px; padding: 16px;
  box-shadow: 0 4px 20px rgba(0,0,0,0.25);
}
.bottom-popover p { margin: 0 0 12px; font-size: 14px; line-height: 1.5; }
/* background: transparent added 2026-08-29, real reported bug: the base
   .btn-outline rule sets background: #fff, and this override only ever
   touched color/border-color -- white text was rendering on a white
   button background, invisible, leaving what looked like a blank box. */
.bottom-popover .btn-outline { background: transparent; color: #fff; border-color: #fff; }

/* ---------- login gate (2026-08-27) ---------- */
.login-gate {
  position: fixed; inset: 0; z-index: 1000;
  background: var(--navy); color: #fff;
  display: flex; align-items: center; justify-content: center;
  padding: 32px 24px; overflow-y: auto;
}
.login-gate-card { max-width: 420px; width: 100%; text-align: center; }
.login-gate-icon { width: 96px; height: 96px; border-radius: 22px; margin-bottom: 24px; }
.login-gate-headline { font-size: 26px; font-weight: 800; line-height: 1.3; margin: 0 0 12px; }
.login-gate-subtext { color: #b9c2dd; font-size: 15px; margin: 0 0 28px; }
.login-gate-form { display: flex; flex-direction: column; gap: 14px; text-align: left; }
.login-gate-form input[type="text"],
.login-gate-form input[type="email"],
.login-gate-form input[type="tel"] {
  padding: 14px 16px; border-radius: 10px; border: 1px solid #3a4a75;
  background: #1c294f; color: #fff; font-size: 16px; width: 100%;
  font-family: inherit; /* type="text" doesn't inherit this the way email/tel already happened to, added 2026-08-29 alongside the Name field style fix */
}
.login-gate-form input::placeholder { color: #8b96b8; }
.hp-field { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.login-gate-consent { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; color: #b9c2dd; }
.login-gate-consent input { margin-top: 3px; flex-shrink: 0; }
.login-gate .btn-primary { padding: 14px; border-radius: 10px; font-size: 16px; border: none; }
.login-gate .form-status { color: #b9c2dd; }

/* ---------- bottom nav ---------- */
.bottom-nav {
  /* z-index added 2026-08-29 -- real reported bug: with no z-index set here
     (defaulted to auto), .card-heart/.detail-heart's explicit z-index:5
     outranked it in the shared stacking context, so a heart icon on a
     scrolled card visually painted ON TOP of this fixed footer bar. 20
     sits comfortably above ordinary page content (hearts at 5) but well
     below the drawer/overlay layers (30+) so the drawer still covers this
     bar correctly when open. */
  position: fixed; bottom: 0; left: 0; right: 0; background: #fff; border-top: 1px solid var(--border);
  z-index: 20;
  display: flex; padding: 10px 0 16px; /* slightly taller, per Aaron's 2026-08-21 request (was 6px 0 10px) */
}
.nav-btn {
  flex: 1; background: none; border: none; display: flex; flex-direction: column; align-items: center;
  gap: 3px; font-size: 10px; color: var(--gray-text); font-weight: 700; cursor: pointer; letter-spacing: 0.3px;
}
.nav-btn.active { color: var(--blue); }
.nav-icon { font-size: 18px; }
/* Icons sized via inline SVG width/height attrs (18px) -- CSS width/height
   here overrides those attrs to bump the bottom-nav icons specifically,
   per Aaron's request, without touching the smaller top-tabs/drawer icons. */
.bottom-nav .nav-icon svg { width: 22px; height: 22px; }
