/* System states (S.state, second wave) on real pages.

   The design draws them inside a 390×844 phone frame, positioned absolutely
   under a 47px status bar. On real pages the same .nd-permit and .nd-state
   pieces, and the offline state, sit in fixed layers instead. Tokens only; the component
   rules themselves come from needt.css (docs/design-system/src/d.css). */

/* ── Offline (screens v4, «Loading & offline», .v4-off): the state in
   place of the page. The figures are hidden, not dimmed — they may be
   wrong by now. The tab bar stays above it. ── */
.nd-offstate {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  align-content: center;
  text-align: center;
  padding: calc(env(safe-area-inset-top, 0px) + 47px) 36px calc(env(safe-area-inset-bottom, 0px) + 120px);
  background: var(--ground);
  color: var(--ink);
}
.nd-offstate[hidden] { display: none; }
.nd-offstate .ic { width: 64px; height: 64px; border-radius: 50%; background: var(--surface-2); display: grid; place-items: center; color: var(--ink-muted); margin: 0 auto 16px; }
.nd-offstate .ic svg { width: 28px; height: 28px; }
.nd-offstate h2 { margin: 0; font-size: 20px; line-height: 26px; font-weight: 600; }
.nd-offstate p { margin: 8px 0 18px; max-width: 320px; font-size: 14px; line-height: 20px; color: var(--ink-muted); }
.nd-offstate .note { margin: 14px 0 0; font-size: 12px; line-height: 16px; }
html.nd-is-offline .nd-main { visibility: hidden; }
html.nd-is-offline .nd-fab { opacity: .4; pointer-events: none; }

/* ── Loading (screens v4: .v4-progress, .v4-skel, .v4-still) — the next
   page is on its way (static/js/loading.js). The bar at once, the tapped
   control dimmed; the skeleton in place of the page after a moment; «Still
   loading…» with Retry over the tab bar when the server is slow. ── */
.nd-loadbar { position: fixed; top: env(safe-area-inset-top, 0px); left: 0; right: 0; height: 3px; z-index: 10090; overflow: hidden; pointer-events: none; }
.nd-loadbar[hidden] { display: none; }
.nd-loadbar i { display: block; height: 100%; width: 0; background: var(--accent); box-shadow: 0 0 8px var(--accent); }
.nd-loadbar.on i { animation: nd-loadfill 4s cubic-bezier(.1, .7, .2, 1) forwards; }
@keyframes nd-loadfill { 0% { width: 0; } 30% { width: 55%; } 100% { width: 88%; } }
[data-nd-nav]:not(.nd-btn) { opacity: .5; transition: opacity var(--dur-fast); }

.nd-skelpage { display: none; }
html.nd-navigating-slow .nd-main { display: none; }
html.nd-navigating-slow .nd-skelpage { display: block; padding: env(safe-area-inset-top, 0px) var(--space-5) 0; }
.nd-skel { border-radius: 12px; background: linear-gradient(90deg, var(--surface-2) 0%, var(--surface-1) 50%, var(--surface-2) 100%); background-size: 200% 100%; animation: nd-skel 1.4s linear infinite; }
.nd-skel.top { height: 20px; width: 36%; margin: 14px auto 22px; }
.nd-skel.t1 { height: 14px; width: 40%; }
.nd-skel.t2 { height: 40px; width: 70%; margin-top: 10px; }
.nd-skel.blk { height: 150px; margin-top: 28px; }
.nd-skel.row { height: 56px; margin-top: 8px; }
.nd-skel.blk + .nd-skel.row { margin-top: 28px; }
@keyframes nd-skel { to { background-position: -200% 0; } }

.nd-still {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 110px);
  transform: translateX(-50%);
  width: min(480px, calc(100% - 40px));
  z-index: 70;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: var(--radius-md);
  background: var(--surface-1);
  box-shadow: var(--shadow-raised);
  font-size: 14px;
  color: var(--ink);
}
.nd-still[hidden] { display: none; }
.nd-still .sp { width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--ink-faint); border-right-color: var(--accent); animation: nd-spin .8s linear infinite; flex: none; }
.nd-still .t { flex: 1; min-width: 0; }
.nd-still .t small { display: block; color: var(--ink-muted); font-size: 12px; }
.nd-still .nd-btn { height: 40px; min-height: 0; padding: 0 14px; font-size: 13px; }
.nd-still .nd-btn[hidden] { display: none; }

/* The reload that brings fresh data is not a new screen: no fade-in. */
html.nd-quiet .page-transition, html.nd-quiet .nd-enter > * { animation: none !important; }

/* ── Busy: an action on its way (static/js/guard.js sets aria-busy) ──
   The button keeps its size and colour; the label gives way to a ring, and a
   second tap does nothing. Disabled-while-busy keeps the primary look — grey
   would read as "you can't", not "working on it". */
.nd-btn[aria-busy="true"] { position: relative; color: transparent !important; }
.nd-btn[aria-busy="true"]::after {
  content: ""; position: absolute; width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--ink); border-right-color: transparent;
  animation: nd-spin .7s linear infinite;
}
.nd-btn.primary[aria-busy="true"]::after { border-color: var(--on-accent); border-right-color: transparent; }
.nd-btn.soft[aria-busy="true"]::after { border-color: var(--accent); border-right-color: transparent; }
.nd-btn.primary[aria-busy="true"]:disabled { background: var(--accent); box-shadow: none; }
.nd-btn.quiet[aria-busy="true"]:disabled { background: var(--surface-2); }
.nd-iconbtn[aria-busy="true"], .nd-li[aria-busy="true"], .nd-chip[aria-busy="true"],
[role="switch"][aria-busy="true"], input[aria-busy="true"] { opacity: .55; transition: opacity var(--dur-fast); }
.nd-main { transition: opacity var(--dur-base) var(--ease-out), filter var(--dur-base) var(--ease-out); }

/* ── Permission: the card over a scrim, as a fixed layer ── */
.nd-permitwrap { position: fixed; inset: 0; z-index: 10078; pointer-events: none; }
.nd-permitwrap .nd-scrim { position: absolute; }
.nd-permitwrap.is-open .nd-scrim { opacity: 1; pointer-events: auto; }
.nd-permitwrap .nd-permit {
  position: absolute;
  max-width: 496px;
  margin: 0 auto;
  bottom: calc(var(--space-6) + env(safe-area-inset-bottom, 0px));
  pointer-events: auto;
}
.nd-permit .nd-btn { min-height: 0; }

/* ── Error pages: a bare page with the state in the middle ── */
body.nd-errorpage { margin: 0; min-height: 100dvh; background: var(--ground); color: var(--ink); }
.nd-errorpage .nd-shell { max-width: 520px; margin: 0 auto; }
.nd-errorpage .nd-state { padding-top: calc(96px + env(safe-area-inset-top, 0px)); }
.nd-state-acts { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2); }
.nd-state a.nd-btn { text-decoration: none; }

@media (prefers-reduced-motion: reduce) {
  .nd-permitwrap .nd-permit, .nd-permit .bell svg, .nd-permit .bell i, .nd-notifpreview, .nd-loadbar.on i, .nd-skel { animation: none; }
  .nd-loadbar.on i { width: 60%; }
  .nd-main { transition: none; }
  .nd-btn[aria-busy="true"]::after { animation-duration: 2.4s; }
}
