/* The flash: what the app says back when something worked. Fizzy's flash and
   submissio's notifications helper arrive at the same shape, and we take it —
   one fixed stack under the header, an ink pill per message, CSS owning the
   whole lifecycle and `animationend` handing the node to the element-removal
   controller. No timer to keep in step with this file.

   The negative variant is the alert; the inline box that shares the sheet
   with a form is a different thing — see banner.css. */
@layer components {
  .flashes {
    position: fixed;
    /* Under the fixed header, not across it — the pill answers something you
       did on the sheet; it is not part of the chrome. */
    inset-block-start: calc(var(--header-height) + var(--block-space-half));
    inset-inline: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--block-space-half);
    z-index: var(--z-overlay);
    /* The stack spans the window; only the pills themselves take the pointer,
       or an invisible band would eat every click along the top of the page. */
    pointer-events: none;
  }

  .flash {
    display: flex;
    align-items: center;
    gap: var(--inline-space);
    max-inline-size: min(60ch, 92vw);
    padding: var(--block-space-half) var(--inline-space-double);
    font-size: var(--text-small);
    color: var(--color-canvas);
    background-color: var(--color-ink);
    border-radius: 100vmax;
    box-shadow: var(--shadow);
    pointer-events: auto;
    /* No fill mode, deliberately. `both` would hold the last keyframe after
       the run — and where something has collapsed the duration to zero
       (Capybara's harness does), the run finishes on the first frame and the
       pill would be left holding `opacity: 0`: present, styled, invisible.
       Without a fill the element keeps its own opacity, and element-removal
       ignores that zero-length animationend, so under a harness the pill
       simply stands until the navigation that follows. In real browsers this
       animation ALWAYS runs — base.css exempts the flash from the
       reduced-motion stilling, a fade being no motion at all — which is what
       lets removal stay one line of JS riding animationend, fizzy's own
       shape. The visible end of a real fade is the last frame before removal,
       in the same task, so nothing flashes back. */
    animation: flash-appear-then-fade var(--flash-life, 4s);
  }

  /* A flash holding a verb holds the stage longer: undo needs time to exist. */
  .flash:has(.flash__undo) {
    --flash-life: 10s;
  }

  .flash--negative {
    color: var(--color-negative-ink);
    background-color: var(--color-negative-tint);
  }

  .flash__undo {
    padding: 0;
    color: inherit;
    font: inherit;
    background: none;
    border: none;
    text-decoration: underline;
    text-underline-offset: 0.15em;
    cursor: pointer;
  }

  @keyframes flash-appear-then-fade {
    0%, 100% { opacity: 0; }
    5%, 60% { opacity: 1; }
  }
}
