/* =====================================================================
 * Extenso OS. Front-end mobile hardening (task #141).
 * ---------------------------------------------------------------------
 * The header, drawer and overlay are authored in a Bricks code element,
 * so their CSS lives in the database rather than in this repo. Rather
 * than edit the Bricks template (which would be overwritten the next
 * time anyone touches the header in the builder), this sheet is loaded
 * last on the front end and corrects the specific rules that misbehave
 * on a phone.
 *
 * Inspected on the live site 2026-07-26. The drawer resolves to:
 *
 *   #extenso-mobile-menu {
 *       display: flex;  position: fixed;  right: 0;  top: 0;
 *       width: 85%;  height: 100vh;  z-index: 999999;
 *       overflow: hidden;
 *       transform: translateX(100%);      <- the only thing hiding it
 *   }
 *   #extenso-mobile-menu.open { transform: translateX(0); }
 *
 * Hiding a panel with transform alone means the panel is still painted,
 * still focusable, still hit-testable, and still occupying real estate
 * immediately past the right edge of the viewport. Anything that lets the
 * page scroll sideways, or that shifts the fixed containing block, puts
 * it back on screen. That is the close button peeking in.
 * ===================================================================== */

/* ---------------------------------------------------------------------
 * 1. SIDEWAYS SCROLL
 *
 * CORRECTION, made after checking this against the live site: the theme
 * ALREADY sets `overflow-x: hidden` on both html and body. The page
 * therefore cannot scroll sideways today, and the original theory here,
 * that scrolling right is what reveals the drawer's close button, does
 * NOT hold. See the note at the head of section 2.
 *
 * The one change worth keeping is hidden -> clip. `overflow: hidden` on
 * html or body silently turns that element into a scroll container, which
 * breaks `position: sticky` on any descendant. `clip` crops with no such
 * side effect. There are zero sticky elements on the site right now, so
 * this changes nothing visible; it removes a trap for the first sticky
 * element anyone adds.
 *
 * No `hidden` fallback is declared here, because the theme already
 * supplies exactly that for browsers too old for clip.
 * ------------------------------------------------------------------ */
html, body {
    overflow-x: clip;
}

/* DELIBERATELY NOT SET: `img, video, iframe { max-width: 100% }`.
 *
 * That is the standard responsive boilerplate and it is wrong for this
 * site. The home page tape marquee (.tape-img, measured at 2951px inside
 * a 2116px viewport) and the post-production parallax hero (.hero-bg,
 * 2244px) are intentionally wider than their containers and are clipped
 * by an ancestor. Capping them at 100% would flatten both effects. The
 * overflow there is a design choice, not a defect. */

/* ---------------------------------------------------------------------
 * 2. THE DRAWER IS ACTUALLY HIDDEN WHEN CLOSED
 *
 * HONEST STATUS: the specific symptom reported ("even when it's hiding,
 * half the cross button is visible") is NOT confirmed diagnosed. It could
 * not be reproduced, because the browser tooling available here would not
 * render the site below about 2100px wide, and the first theory for it
 * (horizontal scroll walking into the parked drawer) was ruled out once
 * the theme was found to already clip horizontal overflow.
 *
 * What IS certain from reading the live CSS is that the drawer is hidden
 * by `transform: translateX(100%)` and nothing else. A transform-only
 * hide leaves the panel painted, focusable, hit-testable, and present in
 * the accessibility tree. That is a real defect on its own terms: tabbing
 * through any page walks the focus ring into an off-screen panel, and
 * taps near the right edge can land on it. It is also the single most
 * common cause of exactly the symptom described.
 *
 * So these rules are the right fix for a real bug, and a plausible but
 * unproven fix for the reported one. Check on a phone after upload; if
 * the close button still peeks, the cause is elsewhere and worth another
 * look with a device that can actually be inspected.
 *
 * transform moves it; visibility removes it from the render and a11y
 * tree; pointer-events stops it swallowing taps near the right edge. The
 * visibility transition is delayed on close so the slide-out is still
 * visible while it animates, then the panel disappears.
 * ------------------------------------------------------------------ */
#extenso-mobile-menu {
    visibility: hidden;
    pointer-events: none;
    transition: transform .32s cubic-bezier(.4, 0, .2, 1), visibility 0s linear .32s;

    /* 100vh on a phone is the viewport WITHOUT the browser chrome
       subtracted, so the bottom of the menu sits under the address bar
       and the last nav item is unreachable. dvh tracks the chrome. */
    height: 100vh;
    height: 100dvh;

    /* The notch and the home indicator. */
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);

    /* A closed drawer should scroll nothing. Open state restores it in
       the rule below, otherwise a long menu cannot be scrolled. */
    overflow-y: hidden;

    /* Belt and braces on the parking position: 1rem past its own width
       so subpixel rounding at fractional viewport widths cannot leave a
       hairline of panel on screen. */
    transform: translateX(calc(100% + 1rem));
}

#extenso-mobile-menu.open {
    visibility: visible;
    pointer-events: auto;
    transform: translateX(0);
    transition: transform .32s cubic-bezier(.4, 0, .2, 1), visibility 0s;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain; /* stops the page behind scrolling too */
}

/* The overlay already carries pointer-events:none while closed, but it
   is display:block below 1200px, so it still participates in layout and
   in the a11y tree. */
#extenso-mobile-overlay {
    visibility: hidden;
    transition: opacity .3s ease, visibility 0s linear .3s;
}
#extenso-mobile-overlay.open {
    visibility: visible;
    pointer-events: auto;
    transition: opacity .3s ease, visibility 0s;
}

/* ---------------------------------------------------------------------
 * 3. TAP TARGETS
 * The burger and the close button are the two controls every phone user
 * must hit. 44x44 CSS px is the floor in both the Apple HIG and WCAG
 * 2.5.5 (AAA) / 2.5.8 (AA, 24px minimum). Anything smaller reads as
 * "the button does not work" rather than "I missed".
 * ------------------------------------------------------------------ */
#mobile-close,
#mobile-toggle.mobile-burger {
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
#mobile-close:focus-visible,
#mobile-toggle.mobile-burger:focus-visible {
    outline: 2px solid #fa5537;
    outline-offset: 3px;
}

/* ---------------------------------------------------------------------
 * 4. THE STICKY BOOKING BAR
 * ---------------------------------------------------------------------
 * .sticky-cta is hand-written into a separate Bricks code element on
 * every page that has it, so every copy drifted. Measured on the live
 * site 2026-07-26:
 *
 *   /packages          z-index 200   appears below 768px
 *   /post-production    z-index 100   appears below 640px
 *   /videography        absent
 *   /studio             absent
 *
 * Different stacking order and different breakpoints on the same
 * component is exactly the "not aligned through all pages" symptom.
 * These rules give every copy one behaviour without touching any of the
 * page templates.
 *
 * The chat launcher sits at z-index 999999. The bar is 100 or 200. So on
 * every page that has the bar, the chat bubble is painted ON TOP of the
 * right-hand end of it, which is precisely where "Start Your Project"
 * lives (the bar is justify-content: space-between). The primary
 * conversion button on mobile is partly covered by a chat bubble. That
 * is the most expensive bug in this file.
 * ------------------------------------------------------------------ */

:root {
    /* One stack, declared once. Everything fixed to a screen edge reads
       its position from here instead of inventing a number. */
    --ext-cta-h: 62px;
    --ext-safe-b: env(safe-area-inset-bottom, 0px);
}

/* Same breakpoint as the burger (1199px), so a tablet does not get the
   mobile nav but the desktop CTA. */
@media (max-width: 1199px) {
    .sticky-cta {
        display: flex;
        z-index: 999900;                 /* above content, below the drawer */
        left: 0;
        right: 0;
        bottom: 0;

        /* Hidden by transform alone in the source, which leaves it
           hit-testable and revealable during iOS overscroll bounce.
           Same defect as the drawer, same fix. */
        visibility: hidden;
        pointer-events: none;
        transition: transform .3s cubic-bezier(.4, 0, .2, 1), visibility 0s linear .3s;
    }

    .sticky-cta.show {
        visibility: visible;
        pointer-events: auto;
        transition: transform .3s cubic-bezier(.4, 0, .2, 1), visibility 0s;
    }

    /* Lift the chat launcher clear of the bar when the bar is showing,
       so it stops covering the CTA button. When the bar is hidden the
       launcher drops back to its normal corner. */
    #ext-chat-scope {
        right: max(16px, env(safe-area-inset-right, 0px)) !important;
        bottom: calc(16px + var(--ext-safe-b)) !important;
        z-index: 999890 !important;
        transition: bottom .3s cubic-bezier(.4, 0, .2, 1);
    }
    body:has(.sticky-cta.show) #ext-chat-scope {
        bottom: calc(var(--ext-cta-h) + 16px + var(--ext-safe-b)) !important;
    }

    /* A fixed bar at bottom:0 permanently covers the last ~62px of the
       page. Without this the footer links and the final paragraph of
       every service page are unreachable on a phone. */
    body:has(.sticky-cta) {
        padding-bottom: calc(var(--ext-cta-h) + var(--ext-safe-b));
    }

    /* Both get out of the way while the nav drawer is open. */
    body.ext-menu-open #ext-chat-scope,
    body.ext-menu-open .sticky-cta {
        opacity: 0;
        pointer-events: none;
    }

    /* The bar is the primary CTA on a phone. Give the button room and
       stop the label wrapping to two lines on a 320px screen. */
    .sticky-cta .btn {
        flex: 0 0 auto;
        white-space: nowrap;
        min-height: 44px;
        display: inline-flex;
        align-items: center;
    }
    .sticky-cta .sc-info { min-width: 0; }
    .sticky-cta .sc-price,
    .sticky-cta .sc-sub {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

/* :has() is unsupported in older Firefox and Safari < 15.4. Those
   browsers keep the launcher in the corner rather than lifting it, which
   is the current behaviour, so nothing regresses. The reserved page
   padding is the part worth having unconditionally. */
@supports not selector(:has(*)) {
    @media (max-width: 1199px) {
        body { padding-bottom: calc(var(--ext-cta-h) + var(--ext-safe-b)); }
        #ext-chat-scope { bottom: calc(var(--ext-cta-h) + 16px + var(--ext-safe-b)) !important; }
    }
}

/* ---------------------------------------------------------------------
 * 5. SCROLL LOCK
 * Opening a full-height drawer while the page behind keeps scrolling is
 * the single most common mobile-menu complaint. position:fixed on body
 * is the only approach that works reliably in iOS Safari; the JS side
 * stores and restores the scroll offset.
 * ------------------------------------------------------------------ */
body.ext-menu-open {
    position: fixed;
    width: 100%;
    overflow: hidden;
}

/* ---------------------------------------------------------------------
 * 6. CONSISTENT PAGE RAILS
 * Reported symptom: "the layout is not aligned through all pages". The
 * fixed header is 90px tall, so every page needs the same offset under
 * it and the same gutter beside it. Pages built at different times in
 * Bricks picked their own numbers.
 * ------------------------------------------------------------------ */
:root {
    --ext-header-h: 90px;
    --ext-gutter: clamp(16px, 5vw, 32px);
}

@media (max-width: 1199px) {
    :root { --ext-header-h: 72px; }

    /* Anchor jumps land under the fixed header instead of behind it. */
    [id] { scroll-margin-top: calc(var(--ext-header-h) + 12px); }
}

/* ---------------------------------------------------------------------
 * 7. iOS INPUT ZOOM
 * Safari zooms the whole page when a focused input has a font-size under
 * 16px. The page never zooms back out, which is why a form can leave the
 * site looking permanently mis-scaled afterwards.
 * ------------------------------------------------------------------ */
@media (max-width: 1199px) {
    input[type="text"], input[type="email"], input[type="tel"],
    input[type="url"], input[type="number"], input[type="password"],
    input[type="search"], input[type="date"], select, textarea {
        font-size: 16px;
    }
}

/* ---------------------------------------------------------------------
 * 8. REDUCED MOTION
 * ------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
    #extenso-mobile-menu,
    #extenso-mobile-overlay {
        transition: none !important;
    }
}
