/* ============================================
   Toast Notifications (platform-standard)
   One card, bottom-left of the content area, single slot
   (newest replaces oldest).

   Brand-free, but no longer status-free. It held zero status
   color so it would read the same for every tenant — but the
   tenant also picks the chrome behind it, and a fixed dark bar
   on a dark sidebar measured 1.03:1. So the card is the page's
   own white, set apart by a border and a shadow instead of by
   a color a tenant can collide with, and the only thing that
   varies is a status rail and glyph. Those use the platform
   status tokens, which branding.py cannot override.

   Self-contained: CSS variable fallbacks let it work on
   pages that don't load main.css (e.g. public booking).
   ============================================ */

.global-toast-container {
    position: fixed;
    /* Pin to the bottom-left corner. top/right are set to auto on purpose so
       no stray utility rule can drag the bar to the top-right — bottom + left
       always win here. */
    top: auto;
    right: auto;
    bottom: var(--spacing-lg, 1.5rem);
    /* The page gutter. This is the whole offset on a page with no sidebar —
       sign-in, public booking — and the base the rail rules below add to. */
    left: var(--spacing-md, 1rem);
    z-index: var(--z-toast, 1090);
    display: flex;
    flex-direction: column;
    pointer-events: none;
    /* The card's width range lives here, not on .global-toast: a fixed box with only
       `left` set shrinks to fit, so a long message stops at 460 and a short one
       is held at 320 rather than shrinking to the size of its own sentence. */
    min-width: 320px;
    max-width: 460px;
}

/* Clear the sidebar, which has two widths. This was one fixed `calc(56px +
   1rem)` — the collapsed width — so an open sidebar covered 184px of the toast,
   and the toast is where a failed action goes to be explained.

   #global-toast-container is a sibling of .global-app-layout, not a child (base.html renders
   it after the block app.html fills), so the state class is read across `~`.
   Below 1024px the sidebar is off-canvas and .global-app-main's margin is 0, so the
   gutter above is already right and these must not apply. */
@media (min-width: 1024px) {
    .global-app-layout ~ .global-toast-container {
        left: calc(var(--sidebar-collapsed-width, 56px) + var(--spacing-md, 1rem));
    }

    .global-app-layout:not(.is-sidebar-collapsed) ~ .global-toast-container {
        left: calc(var(--sidebar-width, 256px) + var(--spacing-md, 1rem));
    }
}

/* display: flex !important predates the .global-toast rename, when Bootstrap's
   .toast:not(.show) { display: none } used to hit this card. The class no
   longer collides, but the !important stays: a cached pre-rename toast.js can
   still stamp the old Bootstrap-colliding class list for a deploy window. */
.global-toast-container .global-toast {
    /* Named once here, used by every part below. The fallbacks are this file's
       self-contained half — a booking page loads no tokens.css — and naming
       them once is what stops that from meaning five copies of each literal. */
    --toast-bg: var(--color-card-bg, #ffffff);
    --toast-border: var(--color-border, #d0d4db);
    --toast-text: var(--color-text, #232323);
    --toast-text-muted: var(--color-text-secondary, #64748b);
    /* The glyph and the message have to share a line box, or the glyph stops
       sitting on the first line's baseline. One value, read by both. */
    --toast-line-height: 1.45;
    /* Info is the base, so it needs no rule of its own — and a toast built by a
       stale cached toast.js, with no status class at all, still gets a rail and
       a glyph that agree with each other. */
    --toast-status: var(--color-info, #6431da);

    display: flex !important;
    align-items: stretch;
    background: var(--toast-bg);
    border: 1px solid var(--toast-border);
    /* The status rail: the left border, widened and colored, so a status
       class only has to name a color. */
    border-left: 3px solid var(--toast-status);
    border-radius: var(--radius-md, 6px);
    /* Deeper and softer than --shadow-lg, whose 0.10 alpha disappears against a
       grey page. A white card on a near-white page is set apart by this and the
       border or by nothing at all, so it is tuned here, not taken from the
       shared elevation step. */
    box-shadow: 0 16px 34px rgba(15, 23, 42, 0.2);
    overflow: hidden;
    pointer-events: auto;
    /* Fill the container so its 320–460px range above decides the card's
       width. (Historically Bootstrap's .toast — a name this card carried
       before the .global-toast rename — pinned every toast to a flat 350px
       because our rule set no width of its own.) */
    width: 100%;

    transform: translateX(-120%);
    opacity: 0;
    transition: transform 0.3s ease-out, opacity 0.3s ease-out;
}

.global-toast-container .global-toast.global-toast-success {
    --toast-status: var(--color-success, #00823a);
}

.global-toast-container .global-toast.global-toast-error {
    --toast-status: var(--color-error, #d9002b);
}

/* Not --color-warning: amber measures 2.15:1 on white, under the 3:1 a
   non-text indicator needs. --status-warning-fg is the same hue darkened
   for exactly this, and it is what the rest of the app already uses. The
   fallback is that token's color-mix flattened, since a booking page has
   neither the mix's inputs nor the token itself. */
.global-toast-container .global-toast.global-toast-warning {
    --toast-status: var(--status-warning-fg, #8a6c31);
}

.global-toast-container .global-toast.is-toast-show {
    transform: translateX(0);
    opacity: 1;
}

.global-toast-container .global-toast.is-toast-hiding {
    transform: translateX(-120%);
    opacity: 0;
}

.global-toast-body {
    display: flex;
    align-items: center;
    gap: var(--spacing-md, 1rem);
    padding: var(--spacing-md, 1rem);
    flex: 1;
    min-width: 0;
    /* A short message keeps its action alongside. A long one would otherwise
       squeeze into a sliver of a column, so the action drops to its own line. */
    flex-wrap: wrap;
}

/* The glyph belongs to the sentence, so it sits inside the wrap boundary above:
   the action may drop to its own line, the icon never does. Without this the
   icon is just another wrappable sibling, and a three-line message pushes it
   onto a line by itself. */
.global-toast-main {
    display: flex;
    align-items: flex-start;
    gap: var(--spacing-sm, 0.5rem);
    flex: 1 1 auto;
    min-width: 0;
}

.global-toast-glyph {
    flex: 0 0 auto;
    color: var(--toast-status);
    font-size: var(--font-size-lg, 0.9375rem);
    line-height: var(--toast-line-height);
}

.global-toast-message {
    font-size: var(--font-size-lg, 0.9375rem);
    /* A literal, not --font-weight-medium: that token is 600, which at this size
       reads as shouting on a white card. Not --font-weight-body either — that
       one tenants can set. The codemod that folds raw 600s into the token has
       no claim on this 500. */
    font-weight: 500;
    line-height: var(--toast-line-height);
    color: var(--toast-text);
    word-break: break-word;
    /* Sized from its own text so flex breaks the line on a long sentence and
       keeps a short one next to its action. */
    flex: 1 1 auto;
    min-width: 0;
}

/* Action = underlined text in the message's own color, nothing more. */
.global-toast-action {
    flex-shrink: 0;
    margin-left: auto;
    background: transparent;
    border: none;
    padding: 0;
    font-size: var(--font-size-md, 0.875rem);
    font-weight: var(--font-weight-medium, 600);
    color: var(--toast-text);
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
}

.global-toast-action:hover,
.global-toast-action:focus-visible {
    color: var(--toast-text-muted);
}

.global-toast-close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    background: transparent;
    border: none;
    border-left: 1px solid var(--toast-border);
    color: var(--toast-text-muted);
    font-size: var(--font-size-xl, 1.25rem);
    cursor: pointer;
    transition: color var(--transition-fast, 0.15s ease);
}

.global-toast-close:hover {
    color: var(--toast-text);
}

@media (max-width: 480px) {
    .global-toast-container {
        left: var(--spacing-sm, 0.5rem);
        right: var(--spacing-sm, 0.5rem);
        bottom: var(--spacing-sm, 0.5rem);
        /* Page gutters at the sides; clear of the home indicator below. */
        inset: auto var(--page-gutter, 1rem)
            calc(var(--safe-bottom, env(safe-area-inset-bottom, 0px)) + var(--spacing-md, 1rem))
            var(--page-gutter, 1rem);
        /* Both gutters are set, so the container is already the width of the
           screen minus them. Carrying a 320px floor through would push a 320px
           phone into a horizontal scroll. */
        min-width: 0;
        max-width: none;
    }
}

/* High-contrast: tokens.css drops the app's shadows here and swaps
   --color-border for near-black, so the card's separation moves entirely
   onto the border. Carrying a 34px shadow through would be the one element
   still casting one. */
@media (prefers-contrast: more) {
    .global-toast-container .global-toast {
        box-shadow: none;
    }
}

/* Respect reduced-motion — appear without sliding. */
@media (prefers-reduced-motion: reduce) {
    .global-toast-container .global-toast {
        transition: opacity 0.3s ease-out;
        transform: none;
    }

    .global-toast-container .global-toast.is-toast-show,
    .global-toast-container .global-toast.is-toast-hiding {
        transform: none;
    }
}

/* Every drawer is a bottom sheet on a phone, and its Cancel/Save row sits on
   the same bottom band the toast does. While a drawer holds the body lock
   (drawer.js sets body.is-drawer-lock while a panel is open) the
   toast moves under the header, so "Saved." never covers the button that saved. */
@media (max-width: 767.98px) {
    /* Above the bottom bar (tokens.css --bottom-bar-h, which already carries
       the home indicator). Wins over the 480px inset above by source order. */
    .global-toast-container {
        bottom: calc(var(--bottom-bar-h, 0px) + var(--spacing-md, 1rem));
    }

    body.is-drawer-lock .global-toast-container {
        inset: calc(
                var(--header-bottom, calc(env(safe-area-inset-top, 0px) + 40px))
                + var(--spacing-sm, 0.5rem)
            )
            var(--page-gutter, 1rem) auto var(--page-gutter, 1rem);
    }
}
