@layer components {
  /* Toasts

     Fixed to the bottom-right corner and out of the flow, so being told
     something never costs the page its position. Bottom-right and not
     bottom-left because the left corner is the view button's, and not
     bottom-centre because the middle of the screen is where the work is.

     The container is inert; only the toasts inside it take the pointer, so
     the empty region does not sit over the page swallowing clicks. */

  .flashes {
    position: fixed;
    z-index: 40;
    bottom: calc(var(--space-3) + var(--safe-bottom));
    right: calc(var(--gutter) + var(--safe-right));
    left: calc(var(--gutter) + var(--safe-left));
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space);
    pointer-events: none;
  }

  .flash {
    pointer-events: auto;
    display: flex;
    align-items: stretch;
    max-width: min(28rem, 100%);
    border-radius: var(--radius);
    border: 1px solid var(--line-strong);
    background: var(--surface);
    box-shadow: var(--shadow-card);
    /* The type on it is the page's secondary size and not its body size: a
       toast is read in one glance from the corner of the eye, and at 19px in
       a box that lifts off the page it starts to argue with the work. */
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    overflow: hidden;
  }

  /* Which kind it is, said on the edge nearest the reader rather than by
     colouring the words: the message stays as legible as any other sentence,
     and green and red never have to carry the meaning by themselves. */
  .flash::before {
    content: "";
    flex: 0 0 auto;
    width: 4px;
    background: var(--go);
  }

  .flash--alert::before { background: var(--danger); }

  .flash__body {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    padding: var(--space-2) var(--space-2) var(--space-2) var(--space-3);
    color: var(--ink);
    text-decoration: none;
  }

  .flash__message { min-width: 0; }

  /* The whole toast is the link, so the cue is a label for what a click does
     rather than the thing you have to hit. */
  /* Set as a label in base.css; here it is the colour that says it is the
     thing to press, and the refusal to be squeezed by the message. */
  .flash__cue { flex: 0 0 auto; color: var(--accent); }

  .flash__body--link:hover { background: var(--surface-hover); }
  .flash__body--link:focus-visible { outline-offset: var(--focus-offset-inset); }

  .flash__close {
    flex: 0 0 auto;
    width: var(--control-h-sm);
    border: 0;
    border-left: 1px solid var(--line);
    background: none;
    color: var(--ink-faint);
    font-size: var(--text-md);
    line-height: 1;
    cursor: pointer;
    transition: background var(--transition), color var(--transition), var(--responds);
  }

  .flash__close:hover { background: var(--surface-hover); color: var(--ink); }
  /* Inset, because the toast has a hard edge and an outset ring would be
     clipped by it. The offset is a token so "inside" is one decision. */
  .flash__close:focus-visible { outline-offset: var(--focus-offset-inset); }

  /* It comes up from the edge it is pinned to and goes back down it. Arriving
     is one declaration rather than a class the controller has to add, so
     nothing has to be in step for a toast to appear.

     The leaving half is outside the motion query on purpose, and it is the one
     thing on this page that changed behaviour rather than only its numbers.
     It used to be inside, so under reduced motion there was no transition at
     all and therefore no transitionend — which is why flash_controller treats
     its timeout as the path that does the removing. On the exit clock it is
     150ms normally and 100ms under reduce, and the transition fires either
     way: the toast still goes, it simply goes without travelling. The comment
     in the controller now says so, and its timeout is a backstop again rather
     than a second path. */
  .flash {
    transition: opacity var(--transition-exit), translate var(--transition-exit);
  }

  .flash--leaving { opacity: 0; }

  @media (prefers-reduced-motion: no-preference) {
    .flash { animation: flash-in var(--transition-enter); }
    .flash--leaving { translate: 0 var(--space); }
  }

  @keyframes flash-in {
    from { opacity: 0; translate: 0 var(--space-2); }
    to   { opacity: 1; translate: none; }
  }

  /* On a phone the view button owns the bottom edge, so the toasts stand on
     top of it instead of beside it, and take the full width they are given. */
  @media (max-width: 48rem) {
    .flashes {
      bottom: calc(var(--space-3) + var(--control-h) + var(--space) + var(--safe-bottom));
      align-items: stretch;
    }

    .flash { max-width: none; }
  }

  .errors { color: var(--danger); font-size: var(--text-sm); }
  .errors ul { margin: 0; padding-inline-start: var(--space-2); }
}
