/* ============================================================================
 * GP Mobile Surface — shared mobile-first surface for portal/app modals
 * ----------------------------------------------------------------------------
 * Replaces desktop-style centered modals on MOBILE with the patterns mandated by
 * docs/MOBILE_DESIGN_SYSTEM.md (§4/§6): a full-screen Push View ("cover") and a
 * Bottom Sheet ("sheet"). DESKTOP keeps the existing centered modal unchanged.
 *
 * Substrate: native <dialog> + showModal() (top layer → renders above the 9999
 * mobile header / 9997 bottom nav with no z-index juggling; free focus-trap,
 * background inert, ::backdrop, ESC). The JS controller is js/gp-surface.js.
 *
 * Adoption: a surface is any element carrying BOTH its legacy modal class (e.g.
 * .gp-modal-overlay) AND `.gp-surface` + `data-gp-surface="cover|sheet"`. The
 * legacy class still drives the DESKTOP look; the rules below take over on mobile.
 *
 * PHASE 1 (pilot): cover mode only, adopted by #addVideoModal on the gymnast
 * profile. Sheet mode is stubbed at the bottom and built in Phase 4 (#6).
 *
 * NOTE (token reconciliation deferred to Phase 5): consumes the wired --gp-*
 * tokens (css/gp-mobile-core.css), not the design-doc --bg-base/--accent-gold
 * names. Do not introduce those here — that is WS-2.5 token-system territory.
 *
 * @package Gymnastics_Plus
 * @since 2.3.47
 * ============================================================================ */

/* ----------------------------------------------------------------------------
 * 1. BASE — make the <dialog> behave like the legacy .gp-modal-overlay
 * ----------------------------------------------------------------------------
 * A <dialog> ships UA styles (border, margin:auto, padding:1em, width/height:
 * fit-content, background:white) that fight the full-bleed overlay. Neutralize
 * only what the .gp-modal-overlay class does NOT already set (it provides
 * position:fixed, inset:0, padding, background dim, blur, z-index, display:none).
 * -------------------------------------------------------------------------- */
dialog.gp-surface {
    max-width: none;
    max-height: none;
    width: auto;
    height: auto;
    margin: 0;
    border: 0;
    color: inherit;
    overflow: visible; /* the inner .gp-modal panel owns scrolling */
}

/* The dialog's own dim (from .gp-modal-overlay background) is the scrim, so the
 * native ::backdrop would double up — keep it transparent. */
dialog.gp-surface::backdrop {
    background: transparent;
}

/* showModal() sets [open] but never the legacy `.active` class, so we must
 * restore the open/visible state the .active rules used to provide:
 *   .gp-modal-overlay        { display:none; opacity:0 }
 *   .gp-modal-overlay.active { display:flex; opacity:1 }
 *   .gp-modal-overlay.active .gp-modal { transform: scale(1) }
 * Specificity dialog.gp-surface[open] (0,2,1) beats .gp-modal-overlay (0,1,0). */
dialog.gp-surface[open] {
    display: flex;
    opacity: 1;
    visibility: visible; /* some surfaces hide via visibility (e.g. .ct-modal) */
}
dialog.gp-surface[open] .gp-modal {
    transform: scale(1);
}

/* The panel is focused on open (js focusPanel) to keep focus inside the dialog
 * without landing on an input (which would pop the keyboard) — it isn't
 * Tab-reachable, so suppress its focus ring (the "blue box"). Real controls
 * keep their own focus rings. */
dialog.gp-surface .gp-modal:focus {
    outline: none;
}

/* When any surface is open, hide the bottom tab nav so a cover is truly the only
 * surface (top-layer already covers it visually; this is belt-and-suspenders and
 * the documented integration hook that replaces mind-lab's per-template override). */
body.gp-surface-open .gp-bottom-nav {
    display: none !important;
}

/* In-surface error banner (data safety: failures never use alert(); the form
 * stays intact and retry-able). Viewport-independent: a surface is a native
 * top-layer <dialog> on EVERY viewport, and a body toast can never paint above
 * the top layer, so this banner is the in-dialog error surface everywhere.
 * (The old "desktop keeps its existing toast" note was wrong: the toast painted
 * UNDER the open dialog. Modal error audit, 2026-07-31.) Hidden until the
 * controller reveals it; colors ride the danger token so dark mode follows. */
.gp-surface__error {
    display: none;
    margin: 0 0 14px;
    padding: 10px 14px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--gp-color-danger) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--gp-color-danger) 35%, transparent);
    color: var(--gp-color-danger);
    font-size: 14px;
    line-height: 1.4;
}
.gp-surface__error.is-visible {
    display: block;
}

/* ----------------------------------------------------------------------------
 * 2. COVER (full-screen push view) — MOBILE ONLY
 * ----------------------------------------------------------------------------
 * 1024px matches css/gp-mobile-single.css (single-page mobile breakpoint). These
 * rules must beat the generic ".gp-modal → bottom sheet" morph in
 * gp-mobile-single.css:426 + gp-profile.css:2122, which use !important — so cover
 * overrides carry !important AND higher specificity (the dialog + attribute).
 * Phase 5 deletes those duplicated morphs and most of these !important fall away.
 * -------------------------------------------------------------------------- */
@media (max-width: 1024px) {

    /* The dialog becomes an opaque, full-bleed container (no dim — the cover IS
     * the screen). align-items:stretch beats the bottom-sheet's flex-end. */
    dialog.gp-surface[data-gp-surface="cover"] {
        padding: 0 !important;
        align-items: stretch !important;
        justify-content: stretch !important;
        background: var(--gp-color-surface) !important;
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
        /* clip, not hidden: same frame-never-scrolls invariant as the sheet
         * (the cover slides up too); the enforcement is _gpFrameScrollLock in
         * js/gp-surface.js — see the sheet frame's note below. */
        overflow: clip !important;
    }

    /* Panel fills the dynamic viewport. 100vh first (old browsers), then 100dvh
     * (modern) so the mobile address-bar resize never clips the footer. */
    dialog.gp-surface[data-gp-surface="cover"] .gp-modal {
        max-width: 100% !important;
        max-height: none !important;
        width: 100% !important;
        height: 100vh !important;
        height: 100dvh !important;
        margin: 0 !important;
        border-radius: 0 !important;
        box-shadow: none !important;
        overflow: hidden !important; /* only .gp-modal-body scrolls (self-contained; some panels set their own overflow) */
        display: flex !important;            /* self-contained: body (flex:1) grows, */
        flex-direction: column !important;   /* footer pins to the bottom (panels outside the profile lack this) */
        transform: translateY(0); /* slide-up target; see @starting-style below */
        transition: transform var(--gp-motion-duration-base) var(--gp-motion-ease-spring);
    }

    /* Native slide-up (bottom → top) where supported; instant + harmless otherwise. */
    @starting-style {
        dialog.gp-surface[data-gp-surface="cover"][open] .gp-modal {
            transform: translateY(100%);
        }
    }

    /* Header = 56px top nav bar. Close control moves to the LEFT (push-view
     * "back" affordance); title sits next to it. Sticky, safe-area aware. */
    dialog.gp-surface[data-gp-surface="cover"] .gp-modal-header {
        position: sticky;
        top: 0;
        z-index: 10;
        display: flex;
        align-items: center;
        justify-content: space-between; /* title left, ✕ right */
        gap: 8px;
        min-height: var(--gp-mobile-header-height, 56px);
        padding: 8px 12px !important;
        padding-top: calc(8px + env(safe-area-inset-top, 0px)) !important;
        background: var(--gp-color-surface);
        border-bottom: 1px solid var(--gp-color-border);
    }
    dialog.gp-surface[data-gp-surface="cover"] .gp-modal-close {
        width: 44px;
        height: 44px;
        min-width: 44px;
        min-height: 44px;
    }
    dialog.gp-surface[data-gp-surface="cover"] .gp-modal-title {
        font-size: 17px;
        line-height: 1.3;
    }

    /* Body scrolls in the remaining space; contain scroll so it never chains to
     * the page behind the surface. */
    dialog.gp-surface[data-gp-surface="cover"] .gp-modal-body {
        flex: 1;
        min-height: 0;
        overflow-y: auto;
        overflow-x: hidden;          /* no left/right movement */
        -webkit-overflow-scrolling: touch;
        overscroll-behavior: none;   /* solid scroll — no rubber-band/bounce, no chaining */
        touch-action: pan-y;         /* vertical panning only (blocks horizontal drag + pinch) */
        padding: 16px !important;
    }

    /* Footer = pinned bottom action bar, safe-area aware, thumb-reachable. */
    dialog.gp-surface[data-gp-surface="cover"] .gp-modal-footer {
        position: sticky;
        bottom: 0;
        z-index: 10;
        flex-shrink: 0;
        gap: 10px;
        padding: 12px 16px !important;
        padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)) !important;
        background: var(--gp-color-bg);
        border-top: 1px solid var(--gp-color-border);
    }
    dialog.gp-surface[data-gp-surface="cover"] .gp-modal-footer .gp-btn-cancel,
    dialog.gp-surface[data-gp-surface="cover"] .gp-modal-footer .gp-btn-save {
        min-height: 44px;
    }

    /* 16px+ inputs inside a cover prevent iOS focus auto-zoom. */
    dialog.gp-surface[data-gp-surface="cover"] .gp-form-input,
    dialog.gp-surface[data-gp-surface="cover"] .gp-form-select,
    dialog.gp-surface[data-gp-surface="cover"] .gp-form-textarea {
        font-size: 16px !important;
    }

    /* iOS gives <input type="date"> an intrinsic width that overflows the field
     * and gets clipped on the right (and was the source of sideways drift before
     * overflow-x:hidden). Constrain it to the container so it fits cleanly. */
    dialog.gp-surface[data-gp-surface="cover"] input[type="date"] {
        -webkit-appearance: none;
        appearance: none;
        width: 100% !important;
        min-width: 0 !important;
        max-width: 100% !important;
        box-sizing: border-box !important;
        text-align: center; /* keep the centered "Jun 4, 2026" look you liked */
    }

    /* Keyboard avoidance: js/gp-surface.js sets --gp-kb-inset to the on-screen
     * keyboard height (VisualViewport) so the pinned footer rides above it. */
    dialog.gp-surface[data-gp-surface="cover"][data-gp-kb="1"] .gp-modal {
        height: calc(100dvh - var(--gp-kb-inset, 0px)) !important;
    }

    /* The in-surface error banner styles moved to the viewport-independent
     * block above (section 1) — the top-layer problem they solve is not a
     * mobile problem. */
    @media (prefers-reduced-motion: reduce) {
        dialog.gp-surface[data-gp-surface="cover"] .gp-modal {
            transition: none;
        }
    }
}

/* ----------------------------------------------------------------------------
 * 3. SHEET (bottom sheet, large detent) — MOBILE ONLY
 * ----------------------------------------------------------------------------
 * Lifts the proven .rb-modal mobile bottom-sheet (template-parts/recruiting/
 * board-styles.php) into the shared surface: bottom-anchored panel, 20px top
 * radius, drag-pill, slide-up, ~90dvh detent, safe-area footer, contained scroll,
 * 16px inputs. Uses `dvh` (not the board's `vh`) so the mobile address bar never
 * clips. Open/close/scroll-lock/a11y/back all come from the same js/gp-surface.js
 * controller — sheet vs cover is pure presentation. Since native-UX F7
 * (2026-07-26) that controller also drives the two sheet GESTURES: drag the panel
 * down past a threshold to dismiss (the drag pill below is now a real affordance,
 * not decoration) and tap the backdrop to dismiss. Do NOT fork either one into a
 * feature's own touch handler; adopt the sheet and both come with it.
 *
 * 1024px breakpoint matches cover (section 2). At ≤768px the board's own .rb-modal
 * mobile rules also match, but these (dialog + attribute, 0,3,1) outrank them and
 * carry !important to beat any generic .gp-modal/.rb-modal morphs — same tactic as
 * cover. Desktop (≥1025px) keeps the legacy centered .rb-modal modal untouched.
 * -------------------------------------------------------------------------- */
@media (max-width: 1024px) {

    /* Transparent, bottom-anchored flex frame; the ::backdrop provides the dim
     * (the page stays visible behind a sheet, unlike the opaque cover). */
    dialog.gp-surface[data-gp-surface="sheet"] {
        padding: 0 !important;
        align-items: flex-end !important;
        justify-content: center !important;
        background: transparent !important;
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
        /* clip, NOT hidden: `hidden` creates a scroll container for the frame,
         * and the frame must never scroll (only .gp-modal-body does). `clip`
         * removes the scroll container by spec. NOTE this alone did NOT fix the
         * WebKit open-bounce: measured in the iOS Simulator, WebKit's async
         * focus scroll writes scrollTop on the clipped box anyway (engine bug),
         * so the invariant is ENFORCED in js/gp-surface.js open() — see
         * _gpFrameScrollLock there for the full story. clip stays because it is
         * the correct declaration and makes the frame inert in Chromium. */
        overflow: clip !important;
    }
    dialog.gp-surface[data-gp-surface="sheet"]::backdrop {
        background: rgba(0, 0, 0, 0.32); /* lighter than the cover dim: a sheet is a partial covering, the page stays readable around it */
    }

    /* Panel: bottom sheet at the large detent (~90dvh), rounded top, slide-up.
     *
     * SOLID, NOT GLASS (2026-07-26). This panel used to paint --gp-glass-bg (a 55-60%
     * alpha tint) plus --gp-glass-blur. Glass is simply the wrong MATERIAL for a
     * sheet, and the failure is not a tuning problem:
     *   1. Even where the blur works, a 55-60% alpha panel over dense, high-contrast
     *      app content still ghosts. Measured on a 390px viewport, changing only the
     *      page behind the sheet changed 98.7% (light) / 99.4% (dark) of the panel's
     *      own pixels, and the sheet's menu labels read tangled with the page text
     *      showing through beneath them.
     *   2. The blur is not guaranteed to happen at all. It degrades to a flat tint in
     *      the iOS WebView (DESIGN.md principle 4) and under reduced-transparency, and
     *      a degraded glass panel is exactly the unreadable raw-alpha case above. A
     *      modal surface cannot have a legibility floor that depends on the engine.
     * A sheet is a modal surface: it must OWN its content, not share it with the page.
     * So the panel takes the solid Tier-2 surface (the same token the cover uses) and
     * a semantic hairline instead of the glass rim. backdrop-filter is set to none
     * because behind an opaque fill it is pure compositing cost for zero pixels.
     * Glass stays on chrome that only ever OVERLAYS content and is never the thing you
     * read through: the floating tab bar, utility bars, toasts. The motion is the
     * signature, not the glass. Do NOT reintroduce --gp-glass-* on a sheet or cover.
     *
     * Verification note, so the next person does not redo it: "backdrop-filter does
     * not work in the browser top layer" is a plausible-sounding but FALSE explanation
     * for this defect. A control (identical glass on a showModal() dialog child vs an
     * ordinary fixed div, same page) renders byte-identically in Chrome, so showModal()
     * is not what broke it. Translucency was. */
    dialog.gp-surface[data-gp-surface="sheet"] .gp-modal {
        max-width: 100% !important;
        width: 100% !important;
        max-height: 90vh !important;
        max-height: 90dvh !important;
        margin: 0 !important;
        border-radius: 20px 20px 0 0 !important;
        background: var(--gp-color-surface) !important;
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
        border-top: 1px solid var(--gp-color-border) !important;
        box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.18) !important;
        overflow: hidden !important; /* only .gp-modal-body scrolls */
        display: flex !important;
        flex-direction: column !important;
        transform: translateY(0); /* slide-up target; see @starting-style below */
        transition: transform var(--gp-motion-duration-base) var(--gp-motion-ease-spring);
    }
    @starting-style {
        dialog.gp-surface[data-gp-surface="sheet"][open] .gp-modal {
            transform: translateY(100%);
        }
    }

    /* Keyboard avoidance (native-UX F4): js/gp-surface.js already sets
     * --gp-kb-inset + data-gp-kb on ANY current surface, cover or sheet — only
     * the cover consumption rule existed (see section 2 above). A bottom sheet
     * is anchored flex-end with its own bounded max-height (~90dvh); without
     * this, an opening keyboard just covers the bottom of the sheet (its
     * footer/input) instead of the sheet shrinking to stay above it. */
    dialog.gp-surface[data-gp-surface="sheet"][data-gp-kb="1"] .gp-modal {
        max-height: calc(90dvh - var(--gp-kb-inset, 0px)) !important;
    }

    /* Header: drag-pill affordance on top (the bottom-sheet "grab" cue), title row
     * below it. Sticky so it (and the pill) stay put while the body scrolls. */
    dialog.gp-surface[data-gp-surface="sheet"] .gp-modal-header {
        position: sticky;
        top: 0;
        z-index: 10;
        flex-shrink: 0;
        padding: 20px 16px 12px !important;
        background: transparent; /* the panel's own solid fill shows through — one uniform surface, no seam under the pill */
    }
    dialog.gp-surface[data-gp-surface="sheet"] .gp-modal-header::before {
        content: '';
        position: absolute;
        top: 8px;
        left: 50%;
        transform: translateX(-50%);
        width: 36px;
        height: 5px;
        border-radius: 3px;
        background: var(--gp-gray-300, #d1d5db);
    }

    /* Body scrolls within the detent; contained so it never chains to the page
     * behind the sheet. Safe-area bottom padding clears the home indicator (the
     * sheet's bottom edge sits on the screen edge). */
    dialog.gp-surface[data-gp-surface="sheet"] .gp-modal-body {
        flex: 1;
        min-height: 0;
        overflow-y: auto;
        overflow-x: hidden;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior: contain;
        touch-action: pan-y;
        padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px)) !important;
    }

    /* 16px+ inputs prevent iOS focus auto-zoom (board fields use the rb-* family). */
    dialog.gp-surface[data-gp-surface="sheet"] .gp-form-input,
    dialog.gp-surface[data-gp-surface="sheet"] .gp-form-select,
    dialog.gp-surface[data-gp-surface="sheet"] .gp-form-textarea,
    dialog.gp-surface[data-gp-surface="sheet"] .rb-form-input,
    dialog.gp-surface[data-gp-surface="sheet"] .rb-form-select,
    dialog.gp-surface[data-gp-surface="sheet"] .rb-form-textarea,
    dialog.gp-surface[data-gp-surface="sheet"] .rb-inline-select {
        font-size: 16px !important;
    }

    @media (prefers-reduced-motion: reduce) {
        dialog.gp-surface[data-gp-surface="sheet"] .gp-modal {
            transition: none;
        }
    }
}
