/* ════════════════════════════════════════════════════════════════════════
   safe-area-polish.css - Proposal 6 (safe-area + standalone-chrome polish)

   PURPOSE
   A small, conservative layer that makes safe-area handling CONSISTENT
   app-wide. It does NOT rewrite the working patterns already in
   styles/shared-prototype.css - it codifies them into shared tokens +
   opt-in utility classes so each page stops hand-rolling its own
   env(safe-area-inset-*) math (the source of the drift the audit flagged:
   a vaarverkeer legend behind the bottom nav, route-detail "Highlights"
   clipped under the top nav).

   WHAT IT REINFORCES (and must never contradict):
   - The floating top nav `.bb-header` is `position:fixed; top:max(12px,
     var(--bb-safe-top))` (shared-prototype.css:127-129).
   - The floating bottom tab bar `.bb-mobile-nav` is `position:fixed;
     bottom:max(12px, var(--bb-safe-bottom))` (shared-prototype.css:514-517).
   - The map stages use the normal-flow `min-height: calc(100dvh + safe)`
     pattern (e.g. vaarverkeer.html:93-94). The BLACK-BAR bug is solved by
     that pattern - this file MUST NOT reintroduce
     `html,body{height:100%;overflow:hidden}` or `position:fixed;inset:0`
     full-bleed stages.

   Because both floating bars start their offset at `max(12px, inset)`, a
   scroll container that wants to clear them must reserve
   `bar-height + 12px-or-inset + a breathing gutter`. The tokens below
   express exactly that so callers never double-count the inset.

   LOAD ORDER: load this AFTER shared-prototype.css so the tokens here can
   reference the ones defined there (--bb-safe-*, --bb-nav-h-*). All rules
   are LOW specificity (single-class / :root) and opt-in - nothing here
   applies unless a page adds the utility class, except the small
   `viewport-fit` left/right safety net which is universally desirable.
   ════════════════════════════════════════════════════════════════════════ */

:root{
  /* Mirror tokens so this file is robust even if it ever loads alone.
     These resolve to the SAME values shared-prototype.css already defines;
     redeclaring is harmless (the later cascade wins, values are identical)
     and guards against a missing-import edge case. */
  --bb-safe-top:    env(safe-area-inset-top, 0px);
  --bb-safe-bottom: env(safe-area-inset-bottom, 0px);
  --bb-safe-left:   env(safe-area-inset-left, 0px);
  --bb-safe-right:  env(safe-area-inset-right, 0px);

  /* App-shell embed safe-top (item #290). When a page runs INSIDE the
     persistent app-shell iframe (pages/app.html), the iframe has NO notch
     inset of its own - `env(safe-area-inset-top)` resolves to 0 - yet the
     SHELL's floating .bb-header still sits at `top:max(12px, REAL safe-top)`
     and floats over the iframe (which fills from y=0). So on a notched
     device the shell header is pushed down by the device inset while the
     embedded page only reserved 12px, and the first content row slid UNDER
     the header. The shell now measures its own real safe-top and injects it
     here as `--bb-embed-safe-top` (see embed() in app.html); the clearance
     token below folds it into the max(). Standalone (no shell) leaves this
     at 0, so nothing changes off-shell. */
  --bb-embed-safe-top: 0px;

  /* The breathing gutter between content and a floating bar (matches the
     +24px / +16px the pages already use; one canonical value now). */
  --bb-content-gutter: 24px;

  /* Canonical clearance a SCROLLING page-body must reserve so its last/first
     element is never hidden under the floating glass bars. The bar itself is
     fixed at `max(12px, inset)` from the edge, so the content reserve is
     `nav-height + that-offset + gutter`. Using max(12px, inset) here keeps it
     identical to the bar's own offset - no double-count. The third max()
     term is the app-shell embed inset (0 off-shell) so the SAME token lands
     content at the SAME y in standalone AND inside the shell (item #290).
     NOTE: this is THE canonical top-clearance token - every plain content
     page (Meer + sub-pages) reserves exactly this so their headers line up. */
  --bb-clear-bottom: calc(var(--bb-nav-h-mobile) + max(12px, var(--bb-safe-bottom)) + var(--bb-content-gutter));
  --bb-clear-top:    calc(max(12px, var(--bb-safe-top), var(--bb-embed-safe-top)) + var(--bb-nav-h-mobile) + 16px);
}

@media (min-width:960px){
  :root{
    /* Desktop swaps to the taller nav and a fixed-in-nav route pill, so the
       bottom tab bar is hidden - desktop bottom clearance is just the gutter. */
    --bb-clear-bottom: 56px;
    --bb-clear-top:    calc(max(12px, var(--bb-safe-top), var(--bb-embed-safe-top)) + var(--bb-nav-h-desktop) + 18px);
  }
}

/* ────────────────────────────────────────────────────────────────────────
   Universal left/right safety net (landscape notch / curved-edge devices).
   With `viewport-fit=cover` the layout viewport extends under the rounded
   corners + sensor housing in landscape. The fixed bars already inset 12px
   on left/right, but full-bleed body content can still tuck under the
   curve. A tiny, harmless horizontal inset on the document keeps text and
   edge controls off the curved glass. Portrait insets are 0 on every
   current device, so this is a no-op there.
   ──────────────────────────────────────────────────────────────────────── */
@supports (padding:max(0px)){
  body{
    padding-left:  max(0px, var(--bb-safe-left));
    padding-right: max(0px, var(--bb-safe-right));
  }
  /* The floating bars are positioned from the edges, not in body flow, so
     the body padding above would shift them inward twice. Cancel it for
     fixed-position chrome by widening their box back to the true edges
     (they already carry their own 12px gutter). */
  .bb-header,
  .bb-mobile-nav{
    margin-left:  calc(-1 * max(0px, var(--bb-safe-left)));
    margin-right: calc(-1 * max(0px, var(--bb-safe-right)));
  }
}

/* ────────────────────────────────────────────────────────────────────────
   Opt-in utility classes. Add to a page's scroll container / body to get
   the canonical clearance without re-deriving the calc(). Use `!important`
   nowhere - these stay low-specificity so a page can still override.
   ──────────────────────────────────────────────────────────────────────── */

/* Reserve clearance for the floating bottom tab bar (mobile) / desktop nav. */
.bb-clear-bottom{ padding-bottom: var(--bb-clear-bottom); }

/* Reserve clearance under the floating top nav. */
.bb-clear-top{ padding-top: var(--bb-clear-top); }

/* Both at once - the common case for a plain scrolling content page. */
.bb-safe-page{
  padding-top:    var(--bb-clear-top);
  padding-bottom: var(--bb-clear-bottom);
}

/* A sticky control row (filter chips, legend toggle) that must sit ABOVE the
   bottom tab bar rather than scroll under it. Mirrors the bar's own offset
   so the two never overlap; the +nav-height lifts it clear of the bar box. */
.bb-stick-above-nav{
  position: sticky;
  bottom: var(--bb-clear-bottom);
}

/* A floating element pinned to the bottom that must clear the home indicator
   AND the tab bar (e.g. a legend card, a "scroll for more" affordance).
   Use on absolutely/fixed-positioned overlays inside a map stage. */
.bb-float-above-nav{
  bottom: var(--bb-clear-bottom);
}
@media (min-width:960px){
  /* No bottom tab bar on desktop - drop back to a plain gutter so floating
     overlays do not sit needlessly high. */
  .bb-float-above-nav{ bottom: var(--bb-content-gutter); }
}

/* Scroll containment for any inner scroll region, so a pull at the top of a
   sheet/list does not trigger the body / PWA chrome (the standalone-caveat
   from Proposal 5e). Opt-in, never on <body>. */
.bb-scroll-area{
  overscroll-behavior: contain;
}
