/* The demo toast. One component, every site, `PLAT-95`.

   A short confirmation in the corner that takes itself away. It is for the
   one class of message nobody has to act on: "the thing you asked for
   happened". Dave's ask, 2026-08-06, about the reset confirmations
   specifically: a banner for those pushes the page down and then sits there
   in front of a room describing housekeeping, when the SC has already moved
   on to the next thing.

   Grown out of `.portal-toast`, which did exactly this for the portal's
   sign-out notice from 2026-07-30 and was renamed here. Nothing about it was
   portal-specific except the name and the palette.

   **THIS FILE IS COPIED PER SITE AND THE COPIES MUST STAY IDENTICAL.** The
   same deal `js/sc-panel.js` takes and for the same reason: each site's
   public tree deploys on its own and there is no shared asset host to point
   at. Nothing in CI enforces it. What keeps the copies byte-identical is that
   the palette is NOT in here: a site themes the toast by setting the four
   `--toast-*` variables in its own stylesheet, and the fallbacks below are
   what a site that sets none of them gets.

   **It needs no JavaScript and that is deliberate.** It removes itself with a
   delayed animation rather than a timer, so it still clears on a page with
   scripting off, and it never has to be told to. `visibility` is animated
   alongside `opacity` so the finished toast stops swallowing clicks aimed at
   whatever is underneath it. A page that wants click-to-dismiss on top of
   that hooks `[data-toast]` itself; portal.js does. */

.demo-toast {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 200;
  max-width: 330px;
  background: var(--toast-bg, #22252B);
  color: var(--toast-text, #FFFFFF);
  border-left: 3px solid var(--toast-edge, #E9A13B);
  border-radius: 6px;
  padding: 12px 15px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .3);
  cursor: pointer;
  animation: demo-toast-in .2s ease-out both,
             demo-toast-out .45s ease-in 5.6s both;
}

/* The failure case. Same six seconds: a reset that did not run is still not
   something to act on from here, it is something to try again or read about
   on the page underneath. */
.demo-toast.is-bad {
  border-left-color: var(--toast-edge-bad, #C62134);
}

.toast-text {
  display: block;
  font: 700 13.5px inherit;
  font-family: inherit;
}

.toast-note {
  display: block;
  margin-top: 3px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--toast-note, #D8DCE3);
}

@keyframes demo-toast-in {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

@keyframes demo-toast-out {
  from { opacity: 1; visibility: visible; }
  to   { opacity: 0; visibility: hidden; }
}

/* No slide, and no fade worth the name, but it must still go away. */
@media (prefers-reduced-motion: reduce) {
  .demo-toast { animation: demo-toast-out .01s linear 6s both; }
}

@media (max-width: 560px) {
  .demo-toast { right: 12px; left: 12px; bottom: 12px; max-width: none; }
}

/* ------------------------------------------------ the standing notification
 *
 * Plan L, 2026-08-12. The same component in the same corner, with one
 * difference: **it does not take itself away.**
 *
 * That is a deliberate departure from the six seconds above and not a
 * regression of it. The two are different classes of message and the rule
 * `PLAT-95` wrote is what separates them: the toast above is for the one class
 * of message nobody has to act on, "the thing you asked for happened, on the
 * page you are looking at". A standing notification is the opposite by
 * construction. It says something you started somewhere else has finished, and
 * it carries the link to go and look at it. Six seconds on a message with a
 * link in it is a message designed to be missed, and the provider it is aimed
 * at is by definition not watching this corner: the whole reason Plan M moves
 * Pre-Visit off `/sync` is so they can walk away.
 *
 * So it waits, and it goes when it is dismissed, or clicked, or the page is
 * left. The row behind it is already stamped seen server-side by the poll that
 * delivered it, so waiting costs nothing and repeats nothing.
 *
 * **The stack, and why the wrapper exists.** Up to three can arrive together,
 * and two `position: fixed` elements in one corner are one element with
 * another one hidden behind it. The wrapper takes the fixed position and the
 * toasts inside it go static, so nothing about the single-toast case above
 * changes. `column-reverse` puts the newest at the bottom, nearest the corner
 * the eye is already on. A page's own one-off toast shares this corner and
 * would overlap; it lives six seconds and the two rarely coincide, which is a
 * known and accepted overlap rather than an oversight. */

.demo-toast-stack {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 200;
  display: flex;
  flex-direction: column-reverse;
  gap: 10px;
  max-width: 330px;
}

.demo-toast-stack .demo-toast {
  position: static;
  right: auto;
  bottom: auto;
  max-width: none;
}

/* No out animation, so no delayed `visibility: hidden` either: it stays where
   it is until something removes the element. */
.demo-toast.is-standing {
  animation: demo-toast-in .2s ease-out both;
  padding-right: 34px;
  /* After the stack rule above, which sets `position: static`, so the close
     button has something to anchor to whether or not it is in a stack. */
  position: relative;
}

.toast-close {
  position: absolute;
  top: 6px;
  right: 8px;
  border: 0;
  background: none;
  padding: 2px 5px;
  font: 400 17px/1 inherit;
  color: var(--toast-note, #D8DCE3);
  opacity: .65;
  cursor: pointer;
}

.toast-close:hover { opacity: 1; }

.toast-link {
  display: inline-block;
  margin-top: 7px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--toast-edge, #E9A13B);
  text-decoration: none;
}

.toast-link:hover { text-decoration: underline; }

.demo-toast.is-bad .toast-link { color: var(--toast-edge-bad, #C62134); }

/* Reduced motion turns the six-second fade above into a near-instant one.
   A standing toast has no fade to shorten, so it only loses its entrance. */
@media (prefers-reduced-motion: reduce) {
  .demo-toast.is-standing { animation: none; }
}

@media (max-width: 560px) {
  .demo-toast-stack { right: 12px; left: 12px; bottom: 12px; max-width: none; }
}
