.pin-gate {
  /* position: fixed (not static in normal flow) so iOS can't scroll the
     page to bring the focused input above the keyboard — that scroll is
     what pushed the title off-screen while leaving the box centered in a
     now-too-short view. --pin-gate-height (js/pin-gate.js) tracks
     visualViewport.height, which shrinks with the on-screen keyboard
     (100dvh doesn't); its companion translateY (also set in JS) follows
     visualViewport.offsetTop, which is how iOS actually reveals the
     keyboard-free area for a fixed element instead of scrolling the page.
     100dvh/translateY(0) are just the fallback before that script runs. */
  position: fixed;
  inset: 0;
  height: var(--pin-gate-height, 100dvh);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-4); padding: var(--space-5); text-align: center;
}
.pin-gate h1 { font-size: var(--text-2xl); color: var(--accent); }
.pin-gate__hint { color: var(--text-muted); font-size: var(--text-sm); }
.pin-gate__input {
  width: 160px; font-size: var(--text-2xl); text-align: center; letter-spacing: 12px;
  padding: var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--bg-elevated); color: var(--text);
}
.pin-gate__error { color: var(--alert); font-size: var(--text-sm); }

/* --app-height (index.html, set from window.innerHeight) is the real
   source of truth — 100dvh is only the fallback for the brief window
   before that inline script runs, or if it doesn't run at all. See the
   comment next to it for why 100dvh alone isn't reliable here. */
#app { display: flex; flex-direction: column; height: var(--app-height, 100dvh); }
#app[hidden] { display: none; }
/* padding-top uses --safe-top (tokens.css) instead of --space-4 so normal
   content still clears the status bar/notch on an installed PWA with
   edge-to-edge enabled (see index.html's apple-mobile-web-app-status-bar-style).
   The day hero banner (css/day.css, .day-hero) is what cancels this and
   bleeds back up past it on purpose, using the same --safe-top so the two
   line up with no seam. Its sticky nav (.dies-detail-nav) is pinned via
   position: fixed instead, so it never touches #view's padding at all. */
/* padding-bottom reserves room for #bottom-nav, which is position: fixed
   (see below) and so no longer takes up space in #app's flex layout. */
#view { flex: 1; overflow-x: hidden; overflow-y: auto; overscroll-behavior-y: contain; padding: var(--space-4); padding-top: var(--safe-top); padding-bottom: calc(var(--space-4) + 64px + env(safe-area-inset-bottom)); }

/* Reusable sticky filter/tab bar for any view scrolling inside #view. The
   ::before extends the opaque background well past the bar's own box so
   iOS's elastic overscroll (rubber-banding past scrollTop 0) can't reveal a
   sliver of whatever card is scrolled behind it. */
.sticky-bar {
  position: sticky;
  top: 0;
  z-index: 10;
  margin: calc(var(--space-4) * -1) calc(var(--space-4) * -1) var(--space-4);
  padding: var(--space-4) var(--space-4) var(--space-2);
  background: var(--bg);
}
.sticky-bar::before {
  content: "";
  position: absolute;
  top: -100vh; left: 0; right: 0; height: 100vh;
  background: inherit;
}

/* position: fixed, not a flex child of #app: #app's height comes from
   --app-height (window.innerHeight, set in index.html), which on an
   installed iOS PWA can under-report the real viewport height in some
   launch/resume paths (the same class of bug --app-height itself was
   introduced to fix — see the comment on #app). When that happens, a
   flex-child nav sits at the bottom of the too-short #app instead of the
   real screen edge, leaving a gap below it that reads as an oversized bar.
   Pinning to the viewport with position: fixed sidesteps that entirely,
   the same fix already used for .dies-detail-nav (css/day.css). */
#bottom-nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 15;
  display: flex; height: calc(64px + env(safe-area-inset-bottom)); padding-bottom: env(safe-area-inset-bottom);
  background: color-mix(in srgb, var(--bg-elevated) 92%, transparent);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--border);
}
#bottom-nav button {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; color: var(--text-muted); transition: color var(--dur-fast) var(--ease-out);
}
#bottom-nav button .nav-icon { font-size: 20px; transition: transform var(--dur-fast) var(--ease-out); }
#bottom-nav button .nav-label { font-size: var(--text-xs); }
#bottom-nav button.active { color: var(--accent); }
#bottom-nav button.active .nav-icon { transform: scale(1.08); }

#login-gate { position: fixed; inset: 0; display: grid; place-items: center; background: var(--bg); z-index: 100; }
#login-gate[hidden] { display: none; }
.login { display: grid; gap: 14px; width: min(320px, calc(100vw - 32px)); }
.login__title { margin: 0; font-size: var(--text-xl); line-height: 1.1; }
.login__field { display: grid; gap: 4px; font-size: var(--text-sm); line-height: 1.2; }
.login__field input { font: inherit; padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px; }
.login__error { margin: 0; color: var(--alert); font-size: var(--text-sm); line-height: 1.3; }
.login__error[hidden] { display: none; }
.login__submit { font: inherit; padding: 12px; border: 0; border-radius: 10px; background: var(--accent-strong); color: #fff; }

#bottom-nav[hidden] { display: none; }

.viatges-view { display: grid; gap: var(--space-4); }
.viatges-view__title { margin: 0; font-family: var(--font-display); font-size: var(--text-2xl); line-height: var(--lh-2xl); }
.viatges-view__offline { margin: 0; color: var(--text-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }
.viatges-view__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.viatges-card {
  display: grid; gap: var(--space-1); padding: var(--space-4);
  background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-sm);
  color: var(--text); text-decoration: none; line-height: var(--lh-base);
}
.viatges-card__title { font-family: var(--font-display); font-size: var(--text-lg); line-height: var(--lh-lg); }
.viatges-card__dates { color: var(--text-muted); font-size: var(--text-sm); line-height: var(--lh-sm); }

.route-loading { margin: 0; padding: var(--space-5) 0; color: var(--text-muted); font-size: var(--text-base); line-height: var(--lh-base); text-align: center; }
.route-error { display: grid; gap: var(--space-3); justify-items: start; padding: var(--space-5) 0; font-size: var(--text-base); line-height: var(--lh-base); }
.route-error p { margin: 0; }
.route-error a { color: var(--accent); }
.route-error__retry {
  padding: var(--space-2) var(--space-4); border-radius: var(--radius-sm);
  background: var(--accent); color: var(--bg-elevated); font-size: var(--text-sm); line-height: var(--lh-sm);
}
