.app-shell {
  /* See the note on `body`: vh is the address-bar-retracted height on both
     mobile browsers, so this stacked with body's own min-height to guarantee
     a phantom scroll on every short page. */
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  /* Prevent any grid row from stretching beyond viewport width */
  grid-template-columns: minmax(0, 1fr);
  /* `clip`, not `hidden`.
   *
   * `overflow-x: hidden` makes the element a scroll container, and a scroll
   * container is what `position: sticky` sticks *inside*. With it set here the
   * sticky header stuck to a box only as tall as itself, so it simply scrolled
   * away with the page — measured at scrollY 300 its top was -300. On a phone
   * that means the cart, the search and the menu leave the screen on the first
   * swipe and only come back by scrolling to the very top.
   *
   * `overflow-x: clip` prevents exactly the same horizontal overflow without
   * creating a scroll container, so sticky keeps working. The `hidden` line
   * before it is the fallback for browsers too old to know `clip`; they get the
   * previous behaviour rather than a sideways-scrolling page. */
  overflow-x: hidden;
  overflow-x: clip;
}

.container {
  width: min(100% - 2rem, var(--container-max));
  margin-inline: auto;
}

/* The header's own appearance lives in system.css, where it is rebuilt.
   What was here was the older version of it, and one line of it was costing
   real money: `backdrop-filter: blur(18px)` on a sticky element that is on
   screen for the whole visit.

   A backdrop filter cannot be cached. The compositor reads back everything
   behind the element, blurs it and recomposites — every frame that anything
   underneath moves, which while scrolling is every frame, on every page.
   `animations.css` already switched it off for touch devices; that left it
   running on every desktop. The replacement is a near-opaque colour, which
   at 92% is indistinguishable from frosted glass and costs nothing.

   `.site-header__row` went with the one-row header it described. */

.site-main {
  padding-block: var(--space-6) var(--space-7);
}

/* Hold the footer down until the page arrives.
   The shell renders header, an empty <main> and the footer in one pass, and
   the router fills <main> a moment later. While it is empty the footer sits
   near the top of the screen, and the homepage hero — 100svh — then shoves it
   down a whole viewport. Measured on a throttled Moto G: one layout shift of
   0.775, which is essentially the entire CLS of the page.

   `:empty` is what keeps this free. It matches only in the window between the
   shell painting and the route rendering; the moment <main> has children the
   rule stops applying, so no rendered page's layout is touched. */
.site-main:empty {
  min-height: 100svh;
}

.site-footer {
  margin-top: var(--space-7);
  padding-block: clamp(4rem, 8vw, 6.5rem);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  background: #0a0a0b;
}

@media (max-width: 768px) {
  .site-header__row {
    min-height: 76px;
  }

  .site-main {
    padding-block: var(--space-5) calc(4rem + env(safe-area-inset-bottom));
  }
}
