/*
 * Toasts — the site's one way of saying "that worked" or "that did not".
 *
 * Everything used to be said in place: a line of text under the form, which on a
 * long form is below the fold by the time you press the button, so the most
 * common outcome — success — was invisible to the person who had just earned it.
 *
 * WHY THE TOP RIGHT, AND NOT THE BOTTOM. The cookie notice is a fixed bar across
 * the bottom of the page and it stays until it is answered, so anything stacked
 * down there is either behind it or shoving it about. The top-right corner is
 * clear at every width, and the toast is given a z-index above the bar anyway, so
 * the two can never argue about which is in front.
 */

.scc-toasts {
    position: fixed;
    /* Clear of the fixed header, and of the admin bar when there is one. */
    inset-block-start: calc(var(--scc-header-h) + var(--scc-admin-bar, 0px) + 1rem);
    inset-inline-end: var(--scc-gutter);
    z-index: 90;                       /* above the cookie bar's 60, below the skip link's 100 */
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    width: min(24rem, calc(100vw - 2 * var(--scc-gutter)));
    /* The stack is a positioner, not a surface: clicks fall through the gaps
       between toasts to the page underneath. Each toast takes its own back. */
    pointer-events: none;
}

.scc-toast {
    pointer-events: auto;
    position: relative;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: start;
    gap: 0.75rem;
    overflow: hidden;
    padding: 0.875rem 1rem;
    border: 1px solid var(--scc-line);
    border-radius: var(--scc-radius);
    background: var(--scc-surface);
    color: var(--scc-text);
    box-shadow: 0 18px 40px rgba(0, 1, 16, 0.55);
}

/* The type is carried by the icon and a spine down the leading edge, not by a
   coloured panel: a wall of green or red at this size reads as an alarm. */
.scc-toast::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    width: 3px;
    background: var(--scc-toast-accent, var(--scc-accent));
}

.scc-toast__icon {
    width: 1.25rem;
    height: 1.25rem;
    margin-block-start: 0.1rem;
    color: var(--scc-toast-accent, var(--scc-accent));
}

.scc-toast__title {
    margin: 0;
    font-size: var(--scc-text-small);
    font-weight: var(--scc-weight-display);
    line-height: 1.35;
    color: var(--scc-text-strong);
}

.scc-toast__text {
    margin: 0.15rem 0 0;
    font-size: var(--scc-text-small);
    line-height: 1.45;
    color: var(--scc-text-muted);
}

.scc-toast__close {
    width: 1.5rem;
    height: 1.5rem;
    display: grid;
    place-items: center;
    padding: 0;
    border: 0;
    border-radius: 0.25rem;
    background: none;
    color: var(--scc-text-muted);
    cursor: pointer;
}
.scc-toast .scc-toast__close:hover,
.scc-toast .scc-toast__close:focus-visible {
    background: rgba(255, 255, 255, 0.10);
    border: 0;
    color: var(--scc-text-strong);
}
.scc-toast__close .scc-icon { width: 0.875rem; height: 0.875rem; }

/* How long is left, drawn rather than guessed at. Paused with the timer when a
   pointer is over the toast, so a toast you are reading cannot leave. */
.scc-toast__timer {
    position: absolute;
    inset-block-end: 0;
    inset-inline: 0;
    height: 2px;
    transform-origin: left center;
    background: var(--scc-toast-accent, var(--scc-accent));
    opacity: 0.5;
    animation: scc-toast-timer linear forwards;
    animation-duration: inherit;
}

@keyframes scc-toast-timer {
    from { transform: scaleX(1); }
    to   { transform: scaleX(0); }
}

.scc-toast--ok    { --scc-toast-accent: #6EE7A8; }
.scc-toast--error { --scc-toast-accent: #FCA5A5; }
.scc-toast--info  { --scc-toast-accent: var(--scc-accent); }

/*
 * IN FROM THE EDGE, OUT THE SAME WAY — as a TRANSITION, never as an animation.
 *
 * The first version faded in with `animation: ... both` and I caught it stranded
 * at frame zero: opacity 0.0004, fully laid out, completely invisible. A renderer
 * that pauses compositing leaves a running animation wherever it stopped, and for
 * a component whose whole job is to be seen that is the one failure that must not
 * be possible.
 *
 * A transition cannot do that. The toast's own declarations ARE the visible
 * state, so anything that stops the motion — a frozen compositor, a dropped
 * class, JavaScript failing between one line and the next — leaves it on screen
 * and readable. The offset state is applied by a class and taken away again; if
 * that never happens the toast is simply there without having slid.
 */
.scc-toast {
    opacity: 1;
    transform: none;
    transition: opacity 0.22s cubic-bezier(0.2, 0.8, 0.3, 1),
                transform 0.22s cubic-bezier(0.2, 0.8, 0.3, 1);
}

.scc-toast.is-entering,
.scc-toast.is-leaving {
    opacity: 0;
    transform: translateX(0.75rem) scale(0.98);
}

.scc-toast.is-leaving { transition-duration: 0.18s; }

/* A phone has no corner to spare: full width under the header. */
@media (max-width: 560px) {
    .scc-toasts {
        inset-inline: var(--scc-gutter);
        width: auto;
    }
}

@media (prefers-reduced-motion: reduce) {
    /* No slide, and no fade to be caught half-way through. The toast is simply
       there. The timer bar stays: it is the one motion that carries information
       rather than decoration. */
    .scc-toast { transition: none; }
    .scc-toast.is-entering { opacity: 1; transform: none; }
    .scc-toast.is-leaving { opacity: 0; transform: none; }
}
