@layer components {
  /* The mobile shell's stack: set only while lib/stack_transition.js runs a slide, never on the desktop. */
  @keyframes stack-enter { from { transform: translateX(100%); } }
  @keyframes stack-leave { to { transform: translateX(-25%); opacity: 0.7; } }

  :root[data-stack="forward"]::view-transition-new(root) {
    animation: stack-enter 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) both;
  }
  :root[data-stack="forward"]::view-transition-old(root) {
    animation: stack-leave 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) both;
  }
  :root[data-stack="back"]::view-transition-old(root) {
    z-index: 1; animation: stack-enter 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) reverse both;
  }
  :root[data-stack="back"]::view-transition-new(root) {
    animation: stack-leave 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) reverse both;
  }

  /* The installed iPhone and iPad app's edge swipe back (lib/back_swipe.js): the screen follows the finger over the
     dimmed shell, then finishes its way or comes back. */
  :root[data-back-swipe] .app-shell { background: var(--muted); }
  :root[data-back-swipe] .app-main {
    background: var(--background);
    box-shadow: -12px 0 24px -16px light-dark(oklch(0 0 0 / 0.35), oklch(0 0 0 / 0.7));
  }
  @media (prefers-reduced-motion: no-preference) {
    :root[data-back-swipe="settling"] .app-main { transition: transform 0.22s cubic-bezier(0.2, 0.8, 0.2, 1); }
  }
  /* A moved screen holds its fixed descendants, so a document's bar would go to the document's end: sticky keeps it
     at the screen's bottom, its margins giving back the viewport's width and the bottom padding. */
  :root[data-back-swipe] .app-main--stack .document-bar {
    position: sticky; bottom: 0;
    margin: 0 calc(50% - 50vw) calc(-1 * var(--stack-clearance));
  }
}
