/* =============================================================================
   Mobile keyboard viewport handling
   -----------------------------------------------------------------------------
   Shared across every page that includes this file.

   The problem: on mobile, when the soft keyboard opens, the "layout
   viewport" does NOT shrink (iOS) and on Android it shrinks only if the
   page opts out of the "resize visual" behaviour. Even when it does
   resize, browsers disagree about WHEN and HOW MUCH, and modals
   (SweetAlert2, Bootstrap) are positioned against the layout viewport,
   so their action buttons end up hidden behind the keyboard.

   The strategy (driven entirely by keyboard-viewport.js):
     1. JS measures the real visible area (visualViewport minus keyboard
        overlap) and publishes it as --kb-visible-height.
     2. CSS uses that variable to constrain scroll containers and to cap
        the height of any element marked as a keyboard-aware surface.
     3. When the keyboard opens, the html/body scroll is locked and the
        focused field is scrolled into the top ~20% of the visible area.

   Every value is a CSS custom property computed at runtime, so nothing
   here depends on a hardcoded pixel height or a magic scroll offset.
   ============================================================================= */

/* --- Root variables ------------------------------------------------------ */
:root {
  /* Height of the area NOT covered by the keyboard. Updated by JS. */
  --kb-visible-height: 100dvh;
  /* Height of the keyboard overlay. Updated by JS. 0 when closed. */
  --kb-keyboard-height: 0px;
  /* Reserved breathing room above the focused field. */
  --kb-scroll-offset: 12px;
  /* Fraction of the visible area the focused field should sit below. */
  --kb-focus-position: 0.2;
  /* Safe-area insets for notched devices. */
  --kb-safe-top: env(safe-area-inset-top, 0px);
  --kb-safe-bottom: env(safe-area-inset-bottom, 0px);
}

/* When the keyboard is open we must keep the document scrollable, because
   the focused field still has to be scrolled INTO view. Locking `overflow`
   here would make programmatic scrolling a no-op and the field would stay
   hidden behind the keyboard.

   Note: we deliberately do NOT set `overflow-x: hidden` on html/body.
   Applying any `overflow` value to the root element re-roots the document
   scroller in some browsers, which silently breaks `window.scrollTo()` -
   exactly what the keyboard handling needs to do. The page is not
   horizontally scrollable anyway, so nothing is lost. */
html.kb-open,
html.kb-open body {
  overscroll-behavior-y: contain;
}

/* --- Generic keyboard-aware scroller --------------------------------------
   Add class "kb-scroll" to any element that should scroll independently
   while the keyboard is open (modal bodies, long forms, step containers). */
.kb-scroll {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  max-height: var(--kb-visible-height);
}

/* --- SweetAlert2 ----------------------------------------------------------
   SweetAlert2 centres the popup inside the *layout* viewport, which on
   iOS still includes the area behind the keyboard. We pull the popup up
   and cap its height so the action row stays reachable. */
html.kb-open .swal2-container {
  /* Constrain the overlay to the visible band, compensating for the layout
     viewport having been panned down. */
  height: var(--kb-visible-height);
  padding-bottom: var(--kb-safe-bottom);
  align-items: flex-start;
  overflow-y: auto;
  overscroll-behavior: contain;
}

html.kb-open .swal2-container.swal2-center > .swal2-popup {
  /* Overrides the library's `place-self: center` so the popup sits in the
     upper part of the visible area instead of behind the keyboard. */
  place-self: start center;
  margin-top: max(10px, var(--kb-scroll-offset));
  max-height: calc(var(--kb-visible-height) - 24px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

html.kb-open .swal2-popup {
  /* Give the action buttons a sticky footer so they stay reachable even
     when the popup body scrolls. */
  padding-bottom: 1.25em;
}

html.kb-open .swal2-popup .swal2-html-container {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

html.kb-open .swal2-popup .swal2-actions {
  position: sticky;
  bottom: 0;
  background: var(--swal2-background, #fff);
  padding-top: 10px;
  margin-top: 10px;
  z-index: 2;
}

html.kb-open .swal2-popup .swal2-actions .swal2-styled {
  min-height: 44px;
}

/* --- Bootstrap modals ---------------------------------------------------- */
html.kb-open .modal {
  /* Bootstrap centres modals against the layout viewport too. */
  align-items: flex-start;

  /* A `position: fixed` element is anchored to the LAYOUT viewport. On iOS
     the keyboard does not shrink that viewport, so a fixed overlay stays
     below the visible band. `visualViewport.offsetTop` is how far the
     layout viewport has been panned down; subtracting it re-anchors the
     overlay to the top of the area the user can actually see.

     The offset is published by keyboard-viewport.js as --kb-viewport-top. */
  top: calc(var(--kb-viewport-top, 0px) * -1);
  height: var(--kb-visible-height);
  max-height: var(--kb-visible-height);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding-top: 8px;
  padding-bottom: 8px;
}

html.kb-open .modal-dialog {
  margin-top: 0;
  margin-bottom: 0;
  max-height: calc(var(--kb-visible-height) - 16px);
  pointer-events: auto;
}

html.kb-open .modal-dialog > .modal-content {
  display: flex;
  flex-direction: column;
  max-height: calc(var(--kb-visible-height) - 16px);
}

html.kb-open .modal-dialog > .modal-content > .modal-body {
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* The header and footer must never be squeezed out by the scrolling body. */
html.kb-open .modal-dialog > .modal-content > .modal-header,
html.kb-open .modal-dialog > .modal-content > .modal-footer {
  flex: 0 0 auto;
}

html.kb-open .modal-dialog > .modal-content > .modal-footer {
  position: sticky;
  bottom: 0;
  z-index: 2;
}

/* --- Off-canvas / custom overlays ---------------------------------------- */
.kb-modal-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  z-index: 1055;
}

html.kb-open .kb-modal-overlay {
  align-items: flex-start;
  height: var(--kb-visible-height);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* --- Focus ring visibility on mobile ------------------------------------- */
@media (max-width: 1024px) {
  /* Prevent the browser from scrolling the focused element to the very
     top of the layout viewport (which ignores the keyboard). JS handles
     the correct positioning instead. */
  .kb-managed input:focus,
  .kb-managed select:focus,
  .kb-managed textarea:focus {
    scroll-margin-top: calc(var(--kb-scroll-offset) + var(--kb-safe-top));
    scroll-margin-bottom: 24px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .kb-scroll,
  .kb-modal-overlay,
  html.kb-open .swal2-popup,
  html.kb-open .modal-dialog > .modal-content > .modal-body {
    scroll-behavior: auto !important;
  }
}
