/* The reset, the safe-area variables, and the #app shell everything else
   sits inside. */

*{box-sizing:border-box;}
/* Paints the status-bar strip so scrolled content never shows through it. */
body::before{content:'';position:fixed;top:0;left:0;right:0;height:var(--sat);
  background:var(--panel);z-index:100;pointer-events:none;}
html,body{margin:0;padding:0;}
body{background:var(--bg);color:var(--ink);font-family:'IBM Plex Sans',sans-serif;-webkit-font-smoothing:antialiased;}
h1,h2,h3{font-family:'Space Grotesk',sans-serif;}
/* --shell-gap is declared in tokens.css with the other variables; this is
   the one place that changes it. 100dvh rather than 100vh because on a phone
   100vh counts browser chrome that has scrolled away, which is the second few
   pixels of the same phantom scrollbar. The 100vh line stays underneath as
   the fallback for anything that does not know dvh. */
#app{max-width:480px;margin:0 auto;background:var(--panel);
  min-height:calc((100vh - var(--shell-gap)) / var(--zoom,1));
  min-height:calc((100dvh - var(--shell-gap)) / var(--zoom,1));
  padding-top:var(--sat);padding-bottom:var(--sab);
  box-shadow:0 0 40px rgba(var(--scrim-ink),.06);position:relative;display:flex;flex-direction:column;
  /* clip, not hidden. overflow:hidden makes this element a scroll container,
     and position:sticky sticks to its nearest scrolling ancestor — so every
     sticky child was sticking to a box that never scrolls, which is the same
     as not being sticky at all. overflow:clip clips without creating one, so
     the header sticks to the window the way it was meant to. */
  overflow:clip;}
@media(min-width:520px){:root{--shell-gap:48px;}body{padding:24px 0;}#app{border-radius:20px;}}

/* The bar and the tabs stick as one block. They were sticky separately, with
   the tabs offset by a hardcoded 53px guess at the bar's height — and the
   guess was wrong, so the ad banner slid half under them. A wrapper has no
   number in it to be wrong. */
