/* Save feedback: the busy button, the progress bar, and the outcome toast.
   Paired with /static/js/form-status.js and app/services/save_status.py.

   WHY THIS IS NOT IN rebrokeros.css, which is otherwise the one place design
   lives: sign-in, MFA, password reset and the CDA wizard are standalone
   Tailwind documents that deliberately do not load the design system, and
   linking it there to pick up three components would restyle the entire
   sign-in flow. Every value below therefore reads an --rb-* token with the
   light-mode literal as its fallback, so the same file renders correctly on a
   page that has the tokens and on one that does not. The tokens themselves are
   still defined in exactly one place — rebrokeros.css.

   A save here is a plain POST that redirects back to the page, and between the
   click and the new page there was no signal whatsoever: the button did not
   change, nothing spun, and the redirect landed the shell's inner scroll pane
   back at the top with the page's own "Saved" banner far below the fold. */


/* ── In flight ──────────────────────────────────────────────────────────── */

.rb-progress {
  position: fixed;
  top: env(safe-area-inset-top, 0px);
  left: 0;
  right: 0;
  height: 2px;
  z-index: 80;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity .12s ease;
}
.rb-progress.is-on { opacity: 1; }
.rb-progress__bar {
  width: 40%;
  height: 100%;
  border-radius: 0 2px 2px 0;
  background: linear-gradient(90deg,
              rgb(var(--rb-accent, 0 121 199) / 0),
              rgb(var(--rb-accent, 0 121 199)));
}
.rb-progress.is-on .rb-progress__bar {
  animation: rb-progress-sweep 1.15s cubic-bezier(.4, 0, .2, 1) infinite;
}
@keyframes rb-progress-sweep {
  from { transform: translateX(-100%); }
  to   { transform: translateX(250%); }
}

/* Inserted as the pressed button's first child, so it works whether the button
   lays its content out as flex or as inline flow. `currentColor` keeps it
   legible on the brand fill and on a bare text button alike. */
.rb-spin {
  display: inline-block;
  flex-shrink: 0;
  width: 12px;
  height: 12px;
  margin-right: 6px;
  vertical-align: -1px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: rb-spin-turn .65s linear infinite;
}
@keyframes rb-spin-turn { to { transform: rotate(360deg); } }

.rb-busy {
  cursor: progress;
  opacity: .72;
  /* The button carries aria-disabled, never `disabled` — see the note in
     form-status.js. This is what makes it behave like one for a pointer; the
     submit guard in that file is what stops a keyboard re-submit. */
  pointer-events: none;
}


/* ── The outcome ────────────────────────────────────────────────────────── */

/* Floating rather than in the flow, deliberately. The inline banners some
   pages render live inside the card they belong to, which comes back
   off-screen; this one cannot. 62px clears the 50px top bar. */
.rb-toast-host {
  position: fixed;
  /* 62px clears the plain 50px header. An impersonation / support session adds
     a banner below that header in normal flow, which a fixed toast would land
     on top of — base.html raises this variable when one is showing. */
  top: calc(env(safe-area-inset-top, 0px) + var(--rb-toast-top, 62px));
  left: 50%;
  transform: translateX(-50%);
  z-index: 70;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: max-content;
  max-width: min(560px, calc(100vw - 24px));
  pointer-events: none;
}
.rb-toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 12px 11px 13px;
  border: 1px solid rgb(var(--rb-line, 226 234 242));
  border-radius: var(--rb-r-md, 10px);
  background-color: rgb(var(--rb-surface, 255 255 255));
  box-shadow: var(--rb-sh-3,
              0 2px 6px rgb(13 27 42 / .08), 0 14px 32px -14px rgb(13 27 42 / .26));
  color: rgb(var(--rb-ink, 13 27 42));
  font-family: var(--rb-font, ui-sans-serif, system-ui, sans-serif);
  font-size: var(--rb-fs-sm, 12.5px);
  line-height: 1.45;
  animation: rb-toast-in .18s ease-out;
}
.rb-toast.is-leaving {
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity .18s ease, transform .18s ease;
}
@keyframes rb-toast-in {
  from { opacity: 0; transform: translateY(-8px); }
}
.rb-toast--success {
  border-color: rgb(var(--rb-good, 15 118 110) / .45);
  background-color: rgb(var(--rb-good-soft, 220 245 241));
}
.rb-toast--error {
  border-color: rgb(var(--rb-bad, 190 18 60) / .45);
  background-color: rgb(var(--rb-bad-soft, 254 226 232));
}
.rb-toast__mark {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin-top: 1px;
}
.rb-toast__mark svg { width: 100%; height: 100%; }
.rb-toast--success .rb-toast__mark { color: rgb(var(--rb-good, 15 118 110)); }
.rb-toast--error   .rb-toast__mark { color: rgb(var(--rb-bad, 190 18 60)); }
.rb-toast__text { flex: 1; min-width: 0; }
.rb-toast__close {
  flex-shrink: 0;
  margin: -4px -3px 0 2px;
  padding: 2px 6px;
  border: 0;
  border-radius: var(--rb-r-sm, 7px);
  background: none;
  color: rgb(var(--rb-ink-3, 128 147 166));
  font-family: inherit;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}
.rb-toast__close:hover { color: rgb(var(--rb-ink, 13 27 42)); }

@media (max-width: 640px) {
  .rb-toast-host {
    left: 12px;
    right: 12px;
    width: auto;
    max-width: none;
    transform: none;
  }
}

/* An indefinite sweep and a spinner are exactly what this setting is about.
   The state still has to be legible, so the elements stay — they just hold
   still, and the button keeps its dimming. */
@media (prefers-reduced-motion: reduce) {
  .rb-progress.is-on .rb-progress__bar {
    animation: none;
    width: 100%;
  }
  .rb-spin { animation: none; }
  .rb-toast { animation: none; }
  .rb-toast.is-leaving { transition: none; }
}
