/* ══════════════════════════════════════════════════════════════════════
   FMC OVERLAY CONTRACT: the layering scale
   ──────────────────────────────────────────────────────────────────────
   One scale, defined once, for the whole Hub. Component stylesheets read
   these properties; they do not invent numbers, and they never raise a
   value to win a stacking contest. Winning one of those is how the next
   collision gets built.

   The order is fixed and it is the order the platform uses:

     content   the page
     sticky    the Primary nav and the BuildingPulse glass nav
     menu      account menu, bell menu, pickers, anything anchored to a
               control that is still part of the page
     tooltip   hover and tap cards. ABOVE their chart, BELOW any modal.
               The trend viewer had its tooltip at 500 and its own sheet
               at 400, which is that rule inverted.
     scrim     the darkening layer
     sheet     bottom-anchored panels
     modal     centred panels
     lightbox  something opened FROM a modal, so it has to clear it
     toast     transient confirmations, above everything they report on
     banner    the impersonation strip, which must never be covered
     system    the update gate and anything else that stops the app

   The values are spaced so a component can sit one step off a layer
   (a modal's close button, say) without reaching the next one.

   NOT on this scale, on purpose: a native <dialog> opened with
   showModal(). It lives in the browser's top layer, above every z-index
   on the page, and giving it one would be decoration. It still needs
   fmc-overlay.js's lock, because the top layer does nothing about the
   page scrolling underneath it on iOS.

   And nothing here can rise above the app's tab bar. That bar is a real
   UIKit tab bar drawn over the web view, so a bottom-anchored sheet
   clears it with room, not with z-index.
   ══════════════════════════════════════════════════════════════════════ */

:root {
  --z-content:  1;
  --z-sticky:   100;
  --z-menu:     200;
  --z-tooltip:  300;
  --z-scrim:    800;
  --z-sheet:    810;
  --z-modal:    820;
  --z-lightbox: 850;
  --z-toast:    900;
  --z-banner:   1000;
  --z-system:   10000;

  /* Room a bottom-anchored or centred overlay has to leave: the home
     indicator on the website, and in the app the real UIKit tab bar drawn
     over the web view, which no z-index can clear. `--app-safe-bottom` is
     pushed from Swift and is absent on the website, so this resolves to
     the indicator inset there and to the bar plus the indicator in the
     app. One property, both surfaces. */
  --ov-bottom-room: max(env(safe-area-inset-bottom, 0px), var(--app-safe-bottom, 0px));
}

/* ── The background lock ───────────────────────────────────────────────
   fmc-overlay.js fixes the body and restores the offset on close; these
   are the parts that belong in CSS rather than in inline styles.

   `overflow: clip` on the root rather than `hidden`: hidden makes the
   root a scroll container, which on iOS re-introduces the rubber band
   the fixed body was there to remove. */
html:has(body.fmc-ov-locked) { overflow: clip; }

body.fmc-ov-locked {
  /* The body is position:fixed while locked, set inline by the script so
     the offset can be exact. Everything else about the lock is here.

     Deliberately NOT `touch-action: none`. It looks like the belt this
     wants and it is a trap: it disables the gesture for every descendant
     too, which is every overlay on the page, and the exception list you
     then need has to name each one. A fixed body has nothing to scroll,
     so the bounce it would suppress is already gone. */
  overscroll-behavior: none;
}

/* ── Scrolling inside an overlay ───────────────────────────────────────
   Any panel that can exceed the viewport needs a viewport-relative
   height and something to scroll, or the gesture has nothing to act on
   and falls through to the background regardless of the lock.

   Viewport-relative, and `dvh` rather than `vh`: on iOS `100vh` is the
   LARGEST viewport height, so a panel sized in vh is taller than the
   visible area and its bottom is unreachable. `dvh` also shrinks when
   the keyboard appears, which matters for every overlay with a field in
   it.

   `overscroll-behavior: contain` stops a scroll that reaches the panel's
   end from chaining to the page. It is the light half of the contract
   and it is not a substitute for the lock: Safari honours it, and a
   panel that is not scrollable at all never generates the scroll for it
   to contain.

   -webkit-overflow-scrolling is deliberately absent. It has been a no-op
   for years and its presence in a rule reads as though it is doing
   something. */
.fmc-ov-scroller {
  max-height: min(90dvh, 860px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* ── Bottom-anchored sheets ────────────────────────────────────────────
   34pt of home indicator on modern phones, plus the app's tab bar where
   there is one. A control that lands under either is unreachable, which
   is not a cosmetic problem. `--app-safe-bottom` is pushed from Swift
   and is 0 on the website, so one rule serves both. */
.fmc-ov-sheet {
  padding-bottom: var(--ov-bottom-room);
}

.fmc-ov-sheet.fmc-ov-scroller {
  max-height: calc(min(90dvh, 860px) - var(--ov-bottom-room));
}

/* ── Scrim ─────────────────────────────────────────────────────────────
   Layer and reach only. Colour, blur and fade stay with the component
   that owns the overlay, because those are design and this file is not.
   `inset: 0` on a fixed element rather than a vh height, for the same
   reason as above. */
.fmc-ov-scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-scrim);
}
