/* -------------------------------------------------------------
   Global toast - rendered in base.html, driven by
   window.showToast(message, type) defined in app.js.
   Self-contained colors so it works on any page.
   Types: info (default) | success | error | warning
   ------------------------------------------------------------- */
.global-toast {
  position: fixed; left: 50%;
  /* Every toast appears at the TOP of the screen and drops down, like a
     native heads-up notification - regardless of type. */
  top: calc(12px + env(safe-area-inset-top, 0px));
  transform: translateX(-50%) translateY(-150%);
  display: flex; align-items: center; gap: 10px;
  width: 96%;
  max-width: none;
  padding: 13px 16px;
  background: #0F1C1A; color: #fff;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 13.5px; font-weight: 600; line-height: 1.4;
  border-radius: 14px;
  box-shadow: 0 10px 28px rgba(15, 28, 26, 0.28);
  opacity: 0; pointer-events: none; z-index: 2000;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.global-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.global-toast-icon { font-size: 19px; line-height: 1; flex-shrink: 0; }
.global-toast-msg { flex: 1; min-width: 0; }

/* Variants */
.global-toast.info .global-toast-icon { color: #5EC4A0; }
.global-toast.success { background: #145E3A; }
.global-toast.success .global-toast-icon { color: #9BE3C5; }
.global-toast.error { background: #A63B2F; }
.global-toast.error .global-toast-icon { color: #FFC9C2; }
.global-toast.warning { background: #6E4A0C; }
.global-toast.warning .global-toast-icon { color: #FFD88A; }

/* Inline spinner for buttons in a busy/submitting state (see app.js
   setButtonBusy). Inherits the button's text color via currentColor. */
.btn-busy-spin {
  display: inline-block;
  width: 15px; height: 15px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  margin-right: 8px;
  vertical-align: -2px;
  animation: btn-busy-rotate 0.8s linear infinite;
}
@keyframes btn-busy-rotate {
  to { transform: rotate(360deg); }
}

/* -------------------------------------------------------------
   Responsive / mobile hardening - loaded on every page via base.html.
   Higher-specificity selectors intentionally override per-page CSS
   so the app stays mobile-friendly across all device widths/heights
   (320px  430px+ and short/tall screens, incl. landscape).
   ------------------------------------------------------------- */

/* Base resets */
html, body {
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;   /* lock both axes - .main-content is the only scroll container */
}
body { -webkit-text-size-adjust: 100%; }

/* Hide scrollbars app-wide (every scroll container, incl. .main-content
   and per-page inner scrollers) while keeping scrolling fully functional.
   WebKit/Blink need the ::-webkit-scrollbar pseudo; Firefox/standard use
   scrollbar-width:none. Older Edge/IE fall back to scrollbar-color
   transparent transparency. */
* {
  scrollbar-width: none;
  scrollbar-color: transparent transparent;
}
*::-webkit-scrollbar {
  width: 0;
  height: 0;
  display: none;
}
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: transparent; }

/* Dark-mode guard for form fields. base.css declares color-scheme:dark under
   prefers-color-scheme: dark, which makes the browser render any input that
   has no explicit colors as a DARK control (grey fill + white text) -
   unreadable inside the app's light sheets/cards once our dark-ink guard
   applies. Pin every bare field to the app's light palette so device theme
   can't repaint them; pages can still override per-field where they
   intentionally use a dark control. */
body input:not([type="checkbox"]):not([type="radio"]),
body textarea,
body select {
  color: #0F1C1A;
  background-color: #FFFFFF;
  color-scheme: light;
}

/* Same dark-mode guard for BARE buttons: under color-scheme:dark the UA
   stylesheet paints unstyled buttons with WHITE text - invisible on the
   app's white sheets/cards. Buttons with their own explicit colors
   (e.g. .btn-save, .nav-item) override this via higher specificity. */
body button {
  color: #0F1C1A;
}

/* Safe-area fallback vars + shared nav height.
   TOP fallback is 0px BY DESIGN: content starts flush at the top of the
   screen. Only devices that actually report a real inset (notched phones
   in standalone mode) shift overlays like toasts / floating buttons. */
:root {
  --safe-area-top: env(safe-area-inset-top, 0px);
  --safe-area-bottom: env(safe-area-inset-bottom, 20px);
  --navbar-height: 72px;
  /* Static default only; app.js republishes the real measured nav height. */
  --nav-measured: var(--navbar-height);
}

/* Known Chromium WebView defect: some wrappers draw the page edge-to-edge
   (viewport extends behind the Android system nav bar) yet report
   safe-area-inset-bottom as 0px. Result: anything pinned to bottom:0 hides
   behind the system UI intermittently as the system bar auto-hides. Until
   the native wrapper stops drawing edge-to-edge, assume a minimum inset
   when running as an installed app so the nav stays tappable and visible.
   NOTE: only the BOTTOM inset is floored - the top stays truly flush. */
@media (display-mode: standalone) {
  :root {
    --safe-area-bottom: max(env(safe-area-inset-bottom, 0px), 24px);
  }
}

/* App frame: fill its width (each page keeps its own max-width) and use
   the dynamic viewport height. 100dvh = modern, 100vh = fallback.
   Flex column keeps .main-content shrinking/scrolling inside the frame;
   the bottom nav itself is NOT part of this flow (see below). */
body .app-frame {
  display: flex;
  flex-direction: column;
  position: relative;
  width: 100%;
  height: 100vh;      /* fallback for older browsers */
  height: 100dvh;     /* dynamic viewport height (mobile) */
  margin: 0 auto;
  overflow: hidden;
}

/* Bottom nav: a FIXED overlay (bottom-nav.css), NOT part of this flow.
   SAME pattern as the CTA bar on property-detail / add-property: the
   scroll container ENDS EXACTLY at the nav's top border. margin-bottom ==
   the nav's measured height (--nav-measured, set by app.js with a static
   65px fallback), so the scroller physically stops above the bar and
   content NEVER passes behind it - no scroll-behind. The nav simply
   occupies the reserved 65px band below the scroller. The 15px is
   interior breathing room inside the scroller, above the bar. Because the
   reserve is a MARGIN (part of the flex layout) rather than inner padding,
   the scroll track itself ends at the bar - like the working CTA pages. */
.app-frame.has-bottom-nav .main-content {
  margin-bottom: var(--nav-measured, var(--navbar-height));
  padding-bottom: 15px;
}

/* Footer spacer: explicit-height div inserted at the bottom of a page's
   main-content so there is always a band of breathing room (same height
   as the standard action button) above the fixed bottom nav. A real div
   with a set height is used so the space can never collapse away. */
.footer-spacer {
  height: 38px;
}

/* Metric variant: My Home uses a bit more breathing room (+10px). */
.footer-spacer.lg {
  height: 48px;
}

/* Universal geometry for EVERY page's scroll container:
   - TOP: per-page breathing room via the --top-pad custom property.
     Default 16px — right for pages that open on a header row
     (greeting, back button + title). Pages override the knob:
       * --top-pad: 0    → full-bleed tops (photo hero, map) so imagery
                            starts at the true screen edge;
       * --top-pad: 28px → immersive centered screens (auth/OTP) whose
                            first element is an icon or heading.
     The old behaviour (safe-area inset + fixed extra) is gone: no notch
     tax in the browser, and each top is chosen for its content.
   - BOTTOM: pages WITHOUT a bottom nav or a fixed CTA bar get 40px of
     interior bottom padding so content never lands flush against the
     screen edge. Nav pages override this above (bar margin pattern). CTA-bar
     pages (property-detail / add-property / share) set their own margin
     reservation in their page stylesheet, so they stay unaffected.
     Explore (the map page) is exempt by design — it has no .main-content. */
body .app-frame .main-content {
  padding-top: var(--top-pad, 16px);
  padding-bottom: 40px;
}

/* -- Theme-responsive bottom nav ----------------------------------
   Follows the device light/dark preference so the nav blends with the
   system navigation bar. Fully opaque background so scrolling content
   never bleeds through. No box-shadow / border - those render as a
   dark "shade" band above the bar when content slides underneath. */
:root {
  --nav-bg: #FFFFFF;
  --nav-item-muted: #8A94A6;
  --nav-item-active: #1D9E6F;
}
@media (prefers-color-scheme: dark) {
  :root {
    --nav-bg: #16191D;
    --nav-item-muted: #9AA3AF;
    --nav-item-active: #3DDC97;
    color-scheme: dark;
  }
}
/* -- Canonical back button ----------------------------------------
   One consistent look on every page: 40px circle, subtle border,
   press-down scale + green tint on tap. The body-prefixed selector
   intentionally outranks per-page .back-btn rules so pages can't drift.
   NOTE: this rule previously had a DANGLING comma merging
   `body .bottom-nav .nav-item.active` into it, which forced the active
   tab into a 40x40 circle - the cause of the "nav bar moves" jump on
   My Home / Chat (longest labels = biggest reflow). Selector removed;
   active-tab styling lives in bottom-nav.css. */
body .back-btn {
  width: 40px; height: 40px; flex-shrink: 0;
  border-radius: 50%;
  background: var(--nav-bg);
  border: 1.5px solid var(--border, #E4EAE8);
  display: flex; align-items: center; justify-content: center;
  color: #0F1C1A;
  font-size: 17px;
  cursor: pointer;
  transition: transform 0.15s ease, background 0.15s ease;
}
body .back-btn:active {
  transform: scale(0.92);
  background: #E8F5EF;
}
@media (prefers-color-scheme: dark) {
  body .back-btn {
    color: #E6E9ED;
    border-color: #2A2F36;
  }
  body .back-btn:active {
    background: #1D2B24;
  }
}

/* Let the scrollable main area actually shrink and scroll inside the
   frame instead of overflowing the viewport. min-height:0 is required
   for flex children to scroll. */
body .app-frame .main-content {
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

/* Avoid iOS auto-zoom when focusing inputs (needs >= 16px) */
body .app-frame input,
body .app-frame select,
body .app-frame textarea {
  font-size: 16px;
}

/* Bottom nav: consistent look + no default tap flash / press jolt on any page.
   -webkit-tap-highlight-color removes the gray flash on tap (mobile).
   user-select:none prevents accidental text selection on the labels.
   line-height is pinned because Firefox and Chrome resolve the icon font's
   default `line-height: normal` differently, making the glyph box taller in
   Firefox - which vertically misaligns the icon+label stack inside the
   flex-column .nav-item. A fixed unitless ratio keeps both engines identical. */
/* Translated labels (e.g. French) can be longer than the English ones.
   Without these rules a long label wraps to a second line, growing the
   flex column and pushing/shrinking the icon above it. Keep every label
   on one clipped line so the icon position is language-independent.
   NOTE: this block previously had a DANGLING comma merging
   `body .bottom-nav .nav-item:active` into the img/video rule below,
   forcing tapped tabs to `max-width:100%; height:auto` mid-press -
   another source of the nav jump. Restored as standalone rules. */
body .bottom-nav .nav-item {
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  line-height: 1.2;
}
body .bottom-nav .nav-item span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* Prevent media from overflowing the frame on narrow screens */
body .app-frame img,
body .app-frame video {
  max-width: 100%;
  height: auto;
}

/* -- Small phones (<= 359px, e.g. 320px) -- */
@media (max-width: 359px) {
  body .app-frame .main-content {
    padding-left: 12px;
    padding-right: 12px;
  }
}

/* -- Compact phones (360-374px) -- */
@media (min-width: 360px) and (max-width: 374px) {
}

/* -- Short screens / landscape (<= 640px tall): keep everything usable -- */
@media (max-height: 640px) {
  body .app-frame .main-content {
    /* top/bottom still governed by the universal rules above (15px bottom pad included) */
  }
}

/* -- Desktop (wider than a phone): consistent dark backdrop so the
      centered phone frame reads as a designed app window -- */
@media (min-width: 431px) {
  body { background: #0d1410; }
}
