/* ================================================================
   Noir — safe-area + keyboard tokens.

   ONE place that knows about notches, home indicators and the software
   keyboard. Everything else reads these variables.

   Loads FIRST (before every component sheet) so the fallbacks exist even
   if noir-viewport.js is blocked; the JS then overwrites them on <html>
   with measured values, which wins because inline style beats a stylesheet.

   Do NOT write raw `env(safe-area-inset-*)` in component CSS again. It was
   spread across 32 places in 3 stylesheets, and because env() silently
   returns 0 without `viewport-fit=cover`, one stray viewport meta tag
   zeroed every one of them at once — which is exactly how the DM header
   ended up under the Dynamic Island.
   ================================================================ */

:root {
  /* CSS-only baseline. noir-viewport.js replaces these with measured px. */
  --noir-safe-top:    env(safe-area-inset-top, 0px);
  --noir-safe-right:  env(safe-area-inset-right, 0px);
  --noir-safe-bottom: env(safe-area-inset-bottom, 0px);
  --noir-safe-left:   env(safe-area-inset-left, 0px);

  /* Keyboard overlap in px. 0 until JS says otherwise — a CSS-only
     browser simply never gets a keyboard-aware layout, which is the
     correct degradation. */
  --noir-kb: 0px;

  /* Visible viewport height. Falls back to svh, the conservative value
     that already excludes persistent browser chrome. */
  --noir-vh: 100svh;
  --noir-vv-top: 0px;

  /* Comfort padding on top of the raw insets, so a bar never sits flush
     against the clock or the home indicator. */
  --noir-bar-pad-top:    8px;
  --noir-bar-pad-bottom: 8px;

  /* Composed values components should actually use. */
  --noir-top-clear:    calc(var(--noir-safe-top) + var(--noir-bar-pad-top));
  --noir-bottom-clear: calc(var(--noir-safe-bottom) + var(--noir-bar-pad-bottom));

  /* Bottom clearance that also rides above the keyboard. When the keyboard
     is open the home indicator is behind it, so the safe-bottom inset must
     NOT be added on top — that would leave a visible gap. */
  --noir-kb-clear: calc(var(--noir-kb) + var(--noir-safe-bottom));
}

/* Keyboard open.
   --noir-kb-clear keeps the full keyboard offset: it is for bars that stay
   full-height and must be LIFTED over the keyboard (`bottom: var(--noir-kb)`).

   --noir-bottom-clear collapses to plain comfort padding, and this is the
   important part: every surface using it is already clear of the keyboard —
   either it lives inside a shell sized to `--noir-vh`, or its own container is
   capped by it. Adding the keyboard height again would double-count, leaving a
   336px gap between the composer and the keys. The home indicator also drops
   out, because the keyboard covers it. */
html[data-noir-kb="open"] {
  --noir-kb-clear: var(--noir-kb);
  --noir-bottom-clear: var(--noir-bar-pad-bottom);
}

/* ── utilities ───────────────────────────────────────────────────
   Add these classes to any fixed bar instead of hand-rolling insets. */
.noir-safe-top    { padding-top:    var(--noir-top-clear) !important; }
.noir-safe-bottom { padding-bottom: var(--noir-bottom-clear) !important; }
.noir-safe-x {
  padding-left:  max(var(--noir-safe-left), 0px);
  padding-right: max(var(--noir-safe-right), 0px);
}

/* A bottom-anchored bar that must stay above the keyboard. */
.noir-kb-anchored {
  bottom: var(--noir-kb) !important;
  padding-bottom: var(--noir-bottom-clear) !important;
  transition: bottom .18s cubic-bezier(.2, .9, .3, 1);
}
@media (prefers-reduced-motion: reduce) {
  .noir-kb-anchored { transition: none; }
}

/* While the keyboard is up, nothing should try to be 100vh tall — that is
   the whole screen including the keyboard, which is what pushes composers
   off the bottom. */
html[data-noir-kb="open"] .noir-vh-fill { height: var(--noir-vh) !important; }

/* A bottom tab bar pinned to `bottom: 0` floats halfway up the screen once
   the keyboard opens, sitting on top of what you're typing. Every native app
   hides it instead — so do we, across all three tab-bar implementations. */
html[data-noir-kb="open"] .noir-mobile-tabbar,
html[data-noir-kb="open"] .nv3-tabbar,
html[data-noir-kb="open"] .noir-mtab-bar {
  display: none !important;
}
/* …and reclaim the scroll padding those bars reserve, or the page keeps a
   tab-bar-sized hole at the bottom while typing. */
html[data-noir-kb="open"] .nv3-tabbar-pad,
html[data-noir-kb="open"] .noir-tabbar-pad {
  height: 0 !important;
}
