/* ============================================================================
   Tier-2 modal shell — shared full-screen-mobile behavior
   ============================================================================
   frontdesk.page has two modal tiers on the public page:
     • Tier 1 — the shared .page-modal system (about, services, faqs, gallery,
       portfolio, contact). Defined in publicPage.css.
     • Tier 2 — bespoke transactional/interactive modals with their own bodies:
       the AI chat (#aiChatModalOverlay), booking (.booking-modal) and custom
       forms (.cfm-modal) modals.

   Each Tier-2 modal keeps its OWN desktop styling, entrance and body (they are
   genuinely different designs). What they share — and used to duplicate, drift
   on, and forget — is the phone behavior: an edge-to-edge full-screen takeover.
   That single cross-cutting concern lives here so a future change lands once.

   WHY THIS FILE LOADS LAST: it is linked after every per-modal stylesheet in
   publicPage.ejs. The rules below are intentionally low-specificity (a single
   id/class each) and rely on source order to win the cascade over each modal's
   own desktop base declarations on phones — including the AI modal's id-based
   rules, which is why #aiChatModal* is grouped in alongside the class selectors.

   Per-modal stylesheets still own (and must keep): desktop sizing/backdrop/
   z-index/entrance, the body, and their FOOTER's safe-area-inset padding (it is
   entangled with each modal's specific footer padding, so it cannot be
   centralized cleanly — see each file's @media (max-width: 767px) block).

   HEADERS ARE NOT TIER-SPECIFIC: booking and custom forms carry BOTH
   .page-modal-header and their own class, so the header row (layout, padding,
   status-bar inset, and the h3's size/weight/colour) is the one Tier-1
   definition in publicPage.css. Their own class now adds only what is genuinely
   bespoke. A new Tier-2 modal should do the same rather than restyle the row.

   ADDING A NEW TIER-2 MODAL: add its overlay + content selectors to the two
   groups below, and also to the scroll-lock list and the modal-chrome observer
   in publicPage.css / Views/partials/publicPage.ejs.

   THE PHONE CONDITION IS DEFINED HERE, and it is not a width alone:

       (max-width: 767px), (max-height: 500px) and (hover: none)

   The second clause is the landscape phone — 844x390, wider than a tablet but
   shorter than half of one. It has to take the takeover for the same reason a
   portrait phone does. `hover: none` keeps a short DESKTOP window — which has no
   on-screen keyboard and no reason to go edge-to-edge — out of it. Every per-modal
   phone block (bookingModal.css, customFormsModal.css, aiChatModal.css) repeats
   this exact condition, and window.fdPhoneModal (Views/partials/publicPage.ejs)
   mirrors it a fourth time. Change one, change all four.
   ========================================================================== */

@media screen and (max-width: 767px), screen and (max-height: 500px) and (hover: none) {
    /* A 44px close/back target on every touch surface, both tiers. The negative
       margin keeps the header's height and the icon's position unchanged, so this
       grows the target without moving anything. Lives here rather than in
       publicPage.css because a landscape phone needs it too, and this file is
       where that condition is defined. */
    .page-modal-close {
        width: 44px;
        height: 44px;
        margin: -4px -4px -4px 0;
    }

    /* Overlay: drop the desktop gutter. The side insets are kept rather than
       zeroed: on a landscape phone the notch is on one SIDE, and an edge-to-edge
       sheet would put the close button or a field under it. They resolve to 0 in
       portrait, so nothing changes there. */
    #aiChatModalOverlay,
    .booking-modal,
    .cfm-modal {
        padding: 0 env(safe-area-inset-right) 0 env(safe-area-inset-left);
        align-items: stretch;
        /* This is the CURTAIN, and it carries NO height on purpose: inset:0
           leaves it exactly the fixed containing block, which is the one box the
           visual viewport is always inside — at every keyboard height and every
           offset iOS pans to while <body> is pinned. It therefore can never be
           short. A `height: 100dvh` here WAS short of it (dvh stops at the
           browser toolbar; the containing block does not), and the card — pushed
           down by visualViewport.offsetTop — was clipped at that edge by the
           overflow:hidden in publicPage.css, leaving bare page in the strip
           between the focused field and the keyboard. Ending flush with the
           visible bottom is the CARD's job; see below.
           White so that wherever the card does not reach — the safe-area gutter,
           the band left while the keyboard animates — the visitor sees this and
           never the page behind. Booking used to keep its 50% black backdrop
           here and showed grey beside a landscape notch. */
        background: #ffffff;
    }

    /* Booking's backdrop is a CHILD at inset:0, so IT — not the white above — is
       what paints in those uncovered strips. Clear it so they match the sheet.
       Custom forms' backdrop already computes to transparent here, and the AI
       modal has no backdrop child. */
    .booking-modal-backdrop {
        background: transparent;
    }

    /* Card: fill the overlay edge-to-edge and end flush with the VISIBLE bottom —
       100dvh, NOT 100% of the curtain above, which is deliberately taller (it is
       the whole containing block, toolbars included). NOTHING overwrites it: the
       card is this height whether or not the keyboard is up, and the browser's own
       reveal scrolls the focused field into the visible area. JS that resized it
       per keyboard frame is what used to break that reveal, and is deleted.
       Dropping the entrance transform/animation
       also keeps the card off its own compositing layer, which on iOS Safari
       otherwise paints a stale offset layer -> dark band above the modal. */
    #aiChatModal,
    .booking-modal-content,
    .cfm-content {
        width: 100%;
        max-width: none;
        height: 100dvh;
        max-height: none;
        border-radius: 0;
        box-shadow: none;
        animation: none;
        transform: none;
        /* No fade either: the booking card kept a 300ms opacity fade behind a
           translucent backdrop, which flashes the page through on dark themes. */
        transition: none;
    }
}

/* Touch devices pin <body> with position:fixed while a modal is open
   (partials/publicPage.ejs); a backdrop-filtered fixed overlay then mispaints on
   iOS (the reason aiChatModal.css already drops its blur on phones). Drop it on
   every touch device, including iPads and landscape phones that are >=768px. */
@media (hover: none) {
    .page-modal-overlay,
    .booking-modal-backdrop,
    .cfm-modal,
    #aiChatModalOverlay,
    .portfolio-detail-overlay {
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

/* One reduced-motion rule for every modal entrance and in-modal animation.
   Lives here because this file loads last and the !important is needed to beat
   the higher-specificity `.booking-modal.open .booking-modal-content` and the
   id-based #aiChatModal rules. */
@media (prefers-reduced-motion: reduce) {
    .page-modal,
    .page-modal-overlay,
    .page-modal-overlay.open .page-modal,
    .booking-modal-content,
    .booking-modal.open .booking-modal-content,
    .cfm-content,
    #aiChatModal,
    .portfolio-detail-inner,
    .portfolio-card,
    .booking-step-content,
    .page-faq-answer,
    .typingIndicator span {
        animation: none !important;
        transition: none !important;
        transform: none !important;
    }
}
