/*
 * Transient notifications. Deliberately self-contained — no palette variables from
 * backend.css or app.css — so the same component renders identically in the host
 * dashboard, the admin area and the public login page, none of which share a palette.
 *
 * Out of the document flow on purpose: a flash message is the result of an action the
 * user just took, and must never push the page it belongs to downwards.
 */
.toasts {
    position: fixed;
    z-index: 1000;
    right: 16px;
    bottom: max(16px, env(safe-area-inset-bottom));
    width: min(400px, calc(100vw - 32px));
    display: flex;
    flex-direction: column-reverse;
    gap: 8px;
    /* The stack must never swallow a click meant for the page underneath it */
    pointer-events: none;
}

@media (max-width: 640px) {
    .toasts {
        left: 16px;
        right: 16px;
        width: auto;
    }
}

.toast {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    overflow: hidden;
    border: 1px solid #DBE1E7;
    border-left: 3px solid var(--toast-accent);
    border-radius: 10px;
    background: #FFFFFF;
    color: #1B242C;
    font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
    font-size: 14px;
    line-height: 1.45;
    box-shadow: 0 6px 20px rgba(20, 24, 28, 0.16);
    pointer-events: auto;
    animation: toast-in 0.18s ease-out both;
}

.toast-success {
    --toast-accent: #2E7D5B;
}

.toast-warning {
    --toast-accent: #A8752E;
}

.toast-error {
    --toast-accent: #B3423B;
}

.toast-icon {
    flex-shrink: 0;
    margin-top: 1px;
    color: var(--toast-accent);
}

.toast-message {
    flex: 1;
    min-width: 0;
}

.toast-close {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin: -2px -4px 0 0;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: none;
    color: #5C6A76;
    cursor: pointer;
}

.toast-close:hover {
    background: #F3F5F7;
    color: #1B242C;
}

/*
 * The shrinking bar is the single source of truth for the lifetime: JavaScript dismisses
 * the toast when the animation ends, so pausing the animation pauses the dismissal.
 * Errors get no bar at all and therefore never disappear on their own.
 */
.toast-life {
    position: absolute;
    left: 0;
    bottom: 0;
    height: 2px;
    width: 100%;
    background: var(--toast-accent);
    opacity: 0.45;
    transform-origin: left;
    animation: toast-life var(--toast-duration, 5s) linear forwards;
}

.toast:hover .toast-life,
.toast:focus-within .toast-life {
    animation-play-state: paused;
}

.toast.is-leaving {
    animation: toast-out 0.15s ease-in both;
}

@keyframes toast-in {
    from {
        opacity: 0;
        transform: translateY(8px);
    }
}

@keyframes toast-out {
    to {
        opacity: 0;
        transform: translateY(6px);
    }
}

@keyframes toast-life {
    to {
        transform: scaleX(0);
    }
}

/*
 * Reduced motion: no slide, and the lifetime bar becomes invisible rather than being
 * removed — the animation still runs, so auto-dismissal keeps working.
 */
@media (prefers-reduced-motion: reduce) {
    .toast,
    .toast.is-leaving {
        animation: none;
    }

    .toast-life {
        opacity: 0;
    }
}

/* Dev only: the Symfony web debug toolbar owns the bottom edge of the screen */
body:has(.sf-toolbar) .toasts {
    bottom: 56px;
}
