/* Shared modal base — overlay mechanics + scroll lock.
 *
 * Extracted from app-shell.css (the overlay mechanics) and mobile-viewport.css
 * (the scroll lock) so a page on any visual system can use the shared modal
 * primitives (VantageModal / VantageLightbox) without adopting a page skin.
 * Load it directly after app-shell.css and before any per-modal sheet
 * (lightbox.css, components.css) — those layer state and skin on top of these
 * base rules and must win.
 */

/* ------------------------------------------------------------------ *
 * Shared modal overlay mechanics (#710)
 *
 * `.vmodal-overlay` (lightbox/inspector skin) and `.modal` (NeXTSTEP dialog
 * skin) were full parallels of each other's overlay mechanics — backdrop
 * sizing, safe-area padding, the show/hide opacity + container scale. Those
 * mechanics live here once; each system keeps only its own backdrop tint and
 * container skin in its sheet. Base comes before the state rules on purpose
 * (display:none must precede .…--active{display:flex} at equal specificity).
 * ------------------------------------------------------------------ */
.vmodal-overlay,
.modal {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    /* `bottom:0`, NOT `height:100vh`. In iOS standalone-PWA portrait the
       displayed area ends at `window.innerHeight` (screen minus status bar) —
       a 100vh overlay lays out ~50pt taller than what is actually shown, so
       the bottom of the modal container gets clipped offscreen (measured on
       device: hard cut at 762pt of an 812pt screen). `bottom:0` sizes the
       overlay to the real renderable viewport in every context (PWA, Safari
       with toolbar, desktop). The strip below it (under the home indicator)
       cannot be painted by ANY element — it shows the document canvas; the
       grey-bar fix for it is `html.scroll-locked` in mobile-viewport.css,
       which recolors the canvas while a modal is open. (#710 saga) */
    bottom: 0;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
    /* Self-sufficient font: the overlay is portaled to <html> at open time
       (see modal.js), so it can't rely on inheriting the body font. */
    font-family: 'Maple Mono', monospace;
    opacity: 0;
    transition: opacity 0.2s ease;
    overflow: hidden;
    overscroll-behavior: contain;
    /* NB: no transform/translateZ here. A `transform` on a position:fixed
       element makes iOS Safari position it relative to the document instead
       of the viewport — so with the body scroll-locked (position:fixed,
       top:-scrollY) the overlay was offset upward by the scroll amount,
       pushing its top under the notch and leaving a gap at the bottom (#710
       follow-up). The fixed overlay is already its own containing block for
       the .modal__overlay / container, so the hint bought nothing. */
    /* Clear the notch / home indicator on notched devices */
    padding-top: max(20px, env(safe-area-inset-top, 20px));
    padding-bottom: max(20px, env(safe-area-inset-bottom, 20px));
    padding-left: max(20px, env(safe-area-inset-left, 20px));
    padding-right: max(20px, env(safe-area-inset-right, 20px));
}

.vmodal-overlay.active,
.modal--active {
    display: flex;
}

.vmodal-overlay.visible,
.modal--visible {
    opacity: 1;
}

.vmodal-container,
.modal__container {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    /* 100%, not a vh cap: resolves against the overlay's safe-area-padded
       content box, so tall content scrolls inside the modal instead of
       running off-screen (header under the notch / footer past the home bar). */
    max-height: 100%;
    transform: scale(0.95);
    transition: transform 0.2s ease;
}

.vmodal-overlay.visible .vmodal-container,
.modal--visible .modal__container {
    transform: scale(1);
}

/* ==========================================================================
   Scroll Lock (applied by scroll-lock.js while a modal is open)
   ========================================================================== */

body.scroll-locked {
    overflow: hidden !important;
    position: fixed;
    left: 0;
    right: 0;
    /* Intentionally no height — JS sets `top: -scrollY` to pin position; constraining
       height clips page content to the viewport and exposes the canvas below. */
    overscroll-behavior: none;
    touch-action: none;
    -webkit-overflow-scrolling: none;
}

/* iOS standalone PWA, portrait (the #710 grey-bar saga): the position:fixed
   scroll-lock is what conjured the grey bar at the bottom. Fixing the body
   collapses the document to exactly viewport height, and iOS standalone
   responds by re-anchoring its (screen − status bar)-tall viewport from
   "below the status bar" (content 50..812pt: page menu bar visible, content
   reaches the screen bottom, no bar) to "top of screen" (content 0..762pt:
   the page slides up under the status bar and iOS natively paints the
   vacated 50pt above the home indicator). That native strip is unpaintable
   by ANY web content — on-device testing ruled out elements (a 100vh
   overlay hard-clips at innerHeight) and the document canvas (an <html>
   background tint applied while locked left the strip untouched).

   So in standalone we keep the body in normal flow and lock scroll at the
   root instead (scroll-lock.js mirrors .scroll-locked onto <html>).
   overflow:hidden on the root clamps the scroll position to 0 while locked
   (the page may visibly sit at its top behind the modal dim);
   scroll-lock.js restores the scroll position on unlock. touch-action from
   the body rule still blocks touch-scroll attempts on page content, and
   the modal overlay lives on <html>, outside the body, so it scrolls
   normally. */
@media (display-mode: standalone) {
    html.scroll-locked {
        overflow: hidden;
    }

    body.scroll-locked {
        position: static;
    }
}
