/* ── CP TOAST ──────────────────────────────────────────────────────────────
   A toast is the receipt for an action the user already committed to: one
   line, past tense, never a question and never a decision point. Driven by
   cp-toast.js, which also replaces the old toastr API.

   Two kinds only: ok (default) and error. The surface is identical, only the
   icon colour changes -- colouring the whole surface red overstates a
   transient message and clashes with the destructive-modal language.

   The surface is INVERSE in light mode and LIFTED in dark mode: #1d2026 is
   near-black against a white page, but in dark mode true black would vanish,
   so #33363c sits ABOVE the dark surface. Either way the toast stays the
   highest-contrast element on the page.
   ------------------------------------------------------------------------ */

:root {
    --cp-toast-inverse: #1d2026;
    --cp-toast-on-inverse: #ffffff;
    --cp-toast-ok: #7ee2a8;
    --cp-toast-bad: #ff9a8f;
}

/* Core sets .dark / .light on <html> (layout.js). Pages without that script
   (Login, Invite, ...) fall back to the OS preference. */
html.dark {
    --cp-toast-inverse: #33363c;
    --cp-toast-on-inverse: #f6f7f9;
    --cp-toast-ok: #6fdc9a;
    --cp-toast-bad: #ff9a8f;
}

@media (prefers-color-scheme: dark) {
    html:not(.light) {
        --cp-toast-inverse: #33363c;
        --cp-toast-on-inverse: #f6f7f9;
        --cp-toast-ok: #6fdc9a;
        --cp-toast-bad: #ff9a8f;
    }
}

/* Bottom-centre, not a corner: the user's attention is on the row or field
   they just touched and bottom-centre is the shortest travel from any of
   them. It also keeps clear of the top-right action cluster of a dialog.
   The 78px float reads as deliberate on a wide screen and keeps clear of the
   planner selection bar (bottom: 24px); on a phone it drops to 48px, see the
   media query at the bottom of this file.

   The host is appended INSIDE the top-most open modal/offcanvas when there is
   one, so it inherits that stacking context and can never render behind the
   surface that produced it. Position stays fixed so a tall, scrolled dialog
   can't push the toast below the fold. */
.cp-toast-host {
    position: fixed;
    /* Centred with auto margins, NOT left:50% + translateX(-50%): a fixed box
       without a width shrink-to-fits against the space left of its offset, so
       left:50% caps it at half the screen and squeezes the text into a tall
       column on mobile. left:0 + right:0 hands it the full width to fit in. */
    left: 0;
    right: 0;
    /* A page with its own fixed bottom bar (the planner selection bar) hands
       up the space it occupies via $CPToast.setLift; the toast then floats
       above it instead of on top of it. 0 when nothing is in the way. */
    bottom: max(78px, var(--cp-toast-lift, 0px));
    width: fit-content;
    margin: 0 auto;
    z-index: 120;
    max-width: 92%;
    pointer-events: none;
}

    /* No modal in play: the toast still has to clear dialogs, offcanvas panels
       and Zebra_Dialog, none of which share a stacking context with <body>. */
    .cp-toast-host.cp-toast-host--page {
        z-index: 100000;
    }

/* Permanent live region: a screen reader announces the toast from here, so
   the visible toast never has to be a live region itself and can render in
   the same frame. Focus is never moved -- it stays where the user left it. */
.cp-toast-announcer {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}

.cp-toast {
    display: flex;
    align-items: center;
    gap: 10px;
    /* Asymmetric on purpose: 16px on the text side, 10px on the button side so
       the button's own padding completes the optical inset. */
    padding: 10px 10px 10px 16px;
    background: var(--cp-toast-inverse);
    color: var(--cp-toast-on-inverse);
    border-radius: 10px;
    /* Fixed in both themes. In dark mode the shadow does little; the surface
       lift carries the elevation instead. */
    box-shadow: 0 12px 30px rgba(0,0,0,.28);
    pointer-events: auto;
    animation: cpToastIn .18s ease;
    text-align: left;
}

    .cp-toast .cp-toast__icon {
        flex: none;
        width: 15px;
        height: 15px;
    }

.cp-toast--ok .cp-toast__icon {
    color: var(--cp-toast-ok);
}

.cp-toast--error .cp-toast__icon {
    color: var(--cp-toast-bad);
}

.cp-toast__body {
    min-width: 0;
}

.cp-toast__msg {
    font-size: 13px;
    font-weight: 500;
    line-height: 1.35;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Server messages are not written to a seven-word budget, so anything long
   (or anything carrying its own <br>) wraps instead of being clipped. */
.cp-toast--wrap .cp-toast__msg {
    white-space: normal;
    overflow: visible;
}

.cp-toast__sub {
    font-size: 11.5px;
    line-height: 1.3;
    opacity: .62;
    margin-top: 1px;
}

/* At most one action, and in this design it is only ever Undo. A translucent
   tint of the surface it sits on, so it adapts to both themes by itself. */
.cp-toast__action {
    flex: none;
    height: 30px;
    padding: 0 12px;
    border: 0;
    border-radius: 8px;
    background: rgba(255,255,255,.14);
    color: inherit;
    font-size: 12.5px;
    font-weight: 700;
    line-height: 30px;
    cursor: pointer;
    white-space: nowrap;
}

    .cp-toast__action:hover,
    .cp-toast__action:focus-visible {
        background: rgba(255,255,255,.22);
    }

    .cp-toast__action:focus-visible {
        outline: 2px solid var(--cp-toast-on-inverse);
        outline-offset: 2px;
    }

/* Keeps the action button off the edge; the 10px right padding alone reads
   tight next to the button's own inset. */
.cp-toast__spacer {
    flex: none;
    width: 2px;
}

@keyframes cpToastIn {
    from {
        opacity: 0;
        transform: translateY(10px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes cpToastFade {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

@media (prefers-reduced-motion: reduce) {
    .cp-toast {
        animation: cpToastFade .18s ease;
    }
}

@media (max-width: 575.98px) {
    .cp-toast-host {
        max-width: calc(100% - 24px);
        /* Closer to the edge than on desktop: there is no room to spare on a
           phone, and the browser chrome already provides the visual footing
           that the 78px float provides on a wide screen. The safe-area inset
           is 0 in a normal browser tab and only kicks in when Core runs
           full-screen from the home screen, where the home indicator sits. */
        bottom: max(calc(48px + env(safe-area-inset-bottom, 0px)), var(--cp-toast-lift, 0px));
    }

    /* Screen width is the scarce resource here, so the optical inset gives way
       to the text: less breathing room left and right than on desktop. The
       whole pill is also a size down - at desktop metrics it reads as a slab
       on a phone and covers the footer of whatever dialog produced it. */
    .cp-toast {
        gap: 7px;
        padding: 7px 8px 7px 11px;
        border-radius: 9px;
    }

        .cp-toast .cp-toast__icon {
            width: 13px;
            height: 13px;
        }

    .cp-toast__msg {
        font-size: 12px;
    }

    .cp-toast__sub {
        font-size: 10.5px;
    }

    .cp-toast__action {
        height: 26px;
        line-height: 26px;
        font-size: 12px;
        padding: 0 10px;
    }

    .cp-toast__msg {
        white-space: normal;
        overflow: visible;
    }
}
