form .alert-block {
    margin-bottom: 1rem;
}

/* ============================================================================
   ALERTS
   One console-banner design serves both shapes: a flat tint of the level
   colour, a hairline in the same colour, a 4px rule down the left edge, 4px
   corners, and body copy in the normal text colour. Colour identifies the
   level; it never carries the words. Each level sets its colour once as a
   custom property and one shared rule consumes it.
   ============================================================================ */

/* Two shapes share these classes: inline page alerts, and the floating
   bootstrap-notify containers ([data-notify="container"], whose alert-<type>
   class is built at runtime). Anything :not([data-notify="container"]) is the
   inline form. */

.alert {
    position: relative;
    margin: 0;
    color: var(--text-primary);
    background-color: var(--alert-base);
}

.alert:not([data-notify="container"]) {
    padding: 0.9rem 1.1rem;
    border: 1px solid;
    border-left: 4px solid;
    border-radius: 4px;
}

/* Console-banner treatment, shared by both shapes: a flat tint of the level
   colour, a matching hairline, a 4px rule down the left edge, and body text in
   the normal text colour — colour identifies the level, it does not carry the
   words. */
.alert-primary:not([data-notify="container"]),
.alert-secondary:not([data-notify="container"]),
.alert-success:not([data-notify="container"]),
.alert-info:not([data-notify="container"]),
.alert-warning:not([data-notify="container"]),
.alert-danger:not([data-notify="container"]),
.alert-dark:not([data-notify="container"]),
.alert-light:not([data-notify="container"]),
.alert-notice:not([data-notify="container"]) {
    background-color: var(--alert-base);
    background-image: linear-gradient(rgba(var(--alert-rgb), var(--alert-tint)),
                                      rgba(var(--alert-rgb), var(--alert-tint)));
    color: var(--text-primary);
    border-color: rgba(var(--alert-rgb), var(--alert-border-alpha, 0.28));
    /* A hue's stripe is its colour; a neutral has none, so it takes the same
       colour knocked back — a full-strength one reads as a white slash. */
    border-left-color: var(--alert-stripe, var(--alert-fg));
}

.alert-primary   { --alert-rgb: var(--bs-primary-rgb);   --alert-fg: var(--bs-primary);
                   --alert-link-fg: var(--color-blue-hover);
                   --alert-link-fg-hover: rgba(var(--bs-primary-rgb), 1);}
.alert-secondary { --alert-rgb: var(--bs-secondary-rgb); --alert-fg: var(--bs-secondary);
                   --alert-link-fg-hover: var(--text-primary);
                   --alert-link-filter: brightness(1.3);
                   --alert-link-filter-hover: brightness(1.5);}
.alert-success   { --alert-rgb: var(--bs-success-rgb);   --alert-fg: var(--bs-success);}
.alert-info      { --alert-rgb: var(--bs-info-rgb);      --alert-fg: var(--bs-info);}
.alert-warning   { --alert-rgb: var(--bs-warning-rgb);   --alert-fg: var(--bs-warning);}
.alert-danger    { --alert-rgb: var(--bs-danger-rgb);    --alert-fg: var(--bs-danger);}
.alert-notice    { --alert-rgb: var(--text-muted-rgb);
                   --alert-fg: var(--text-muted);
                   --alert-border-alpha: 0.5; }

/* The two neutral levels. Same banner as every hue above — only the colour
   is a weight on the text ramp instead of a hue, so they sit in a stack of
   alerts at the same weight rather than as slabs. */
.alert-light     { --alert-rgb: var(--bs-light-rgb);     --alert-fg: var(--bs-light);
                   --alert-stripe: rgba(var(--bs-light-rgb), 0.45);
                   --alert-link-underline-hover: 0.7; }
.alert-dark      { --alert-rgb: var(--bs-dark-rgb);      --alert-fg: var(--bs-dark-fg);
                   --alert-link-fg-hover: var(--text-primary);
                   --alert-link-underline: 0.3; --alert-link-underline-hover: 0.6; }

/* dark is the one level that is a well rather than a tint, so it paints the
   surface solid — the same paintable well (--bs-dark-well) every other
   *-dark variant uses, with the same hairline edge. */
.alert-dark:not([data-notify="container"]),
.alert[data-notify="container"].alert-dark {
    background-color: var(--bs-dark-well);
    background-image: none;
    color: var(--bs-dark-fg);
    border-color: var(--btn-dark-border);
    border-left-color: rgba(var(--bs-dark-fg-rgb), 0.4);
}

/* success/warning/danger/info links brighten on top of their variant colour. */
.alert-success, .alert-warning, .alert-danger, .alert-info {
    --alert-link-filter: brightness(1.2);
    --alert-link-filter-hover: brightness(1.4);
}

/* bootstrap-notify icon: a bare glyph in the level colour, optically centred
   against the text block rather than sat in a puck. */
.alert [data-notify="icon"] { display: block; }

.alert [data-notify="icon"]:before {
    position: absolute;
    left: 16px;
    top: 50%;
    transform: translateY(-50%);
    display: block;
    width: auto;
    height: auto;
    line-height: 1;
    font-size: 1rem;
    background: none;
    color: var(--alert-fg);
}

.alert [data-notify="title"] {
    display: block;
    color: inherit;
    font-weight: 650;
    font-size: 14px;
    margin-bottom: 2px;
}

/* Empty when Django sends a message with no title — collapse it so it costs
   no vertical space. */
.alert [data-notify="title"]:empty { display: none; }

.alert [data-notify="message"] {
    font-size: 14px;
    color: inherit;
}

/* Alert links */
.alert-primary .alert-link, .alert-secondary .alert-link,
.alert-success .alert-link, .alert-info .alert-link,
.alert-warning .alert-link, .alert-danger .alert-link,
.alert-dark .alert-link, .alert-light .alert-link {
    color: var(--alert-link-fg, var(--alert-fg));
    font-weight: 600;
    text-decoration: underline;
    text-decoration-color: rgba(var(--alert-rgb), var(--alert-link-underline, 0.4));
    text-underline-offset: 2px;
    transition: all 0.2s ease;
    filter: var(--alert-link-filter, none);
}

.alert-primary .alert-link:hover, .alert-secondary .alert-link:hover,
.alert-success .alert-link:hover, .alert-info .alert-link:hover,
.alert-warning .alert-link:hover, .alert-danger .alert-link:hover,
.alert-dark .alert-link:hover, .alert-light .alert-link:hover {
    color: var(--alert-link-fg-hover, var(--alert-link-fg, var(--alert-fg)));
    text-decoration-color: rgba(var(--alert-rgb), var(--alert-link-underline-hover, 0.8));
    filter: var(--alert-link-filter-hover, var(--alert-link-filter, none));
}

/* Floating notifications wear the same console-banner treatment as the inline
   alerts — same tint, same hairline, same 4px left rule, same 4px corners —
   and add only what floating requires: a drop shadow and an opaque-enough
   surface to sit over page content. Clicking anywhere dismisses one, hence the
   pointer.

   !important on padding: bootstrap-notify writes `padding-left: 65px` inline
   on every container from its placement() routine, sized for the 35px icon
   puck this design does not have. */
.alert[data-notify="container"] {
    padding: 0.9rem 2.5rem 0.9rem 42px !important;
    background-color: var(--notify-surface);
    background-image: linear-gradient(rgba(var(--alert-rgb), var(--alert-tint)),
                                      rgba(var(--alert-rgb), var(--alert-tint)));
    color: var(--text-primary);
    border: 1px solid rgba(var(--alert-rgb), var(--alert-border-alpha, 0.28));
    border-left: 4px solid var(--alert-fg);
    border-radius: 4px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
    backdrop-filter: blur(12px);
    cursor: pointer;
    /* !important: bootstrap-notify writes z-index inline on the container. */
    z-index: 9999999 !important;
}

/* bootstrap-notify's template sizes the toast with grid classes
   (col-10 col-xs-11 col-sm-4), so its max width is a percentage of the
   viewport: 33% from 576px up. On a narrow window that is a couple of hundred
   pixels, and the copy wraps into a squished column beside 82px of padding.
   Size it in pixels instead, floored so short messages stay one line and
   clamped to the viewport so it never overflows a phone. */
.alert[data-notify="container"] {
    width: auto;
    min-width: min(320px, calc(100vw - 40px));
    max-width: min(460px, calc(100vw - 40px));
}

/* !important: the dismiss button carries inline `top: 5px` from
   bootstrap-notify's styleDismiss(); a single-line toast wants it centred. */
.alert[data-notify="container"] .close {
    top: 50% !important;
    transform: translateY(-50%);
}

/* Close button: ghost on every alert — muted glyph, no fill at rest, a faint
   wash of the alert's own colour on hover. */
.alert .close {
    top: 0;
    width: auto;
    height: auto;
    padding: 0.25rem 0.4rem;
    font-size: 1.15rem;
    line-height: 1;
    opacity: 1;
    color: var(--text-muted);
    text-shadow: none;
    background: transparent;
    border: none;
    border-radius: 6px;
    transition: color 150ms ease-out, background-color 150ms ease-out;
}

.alert .close:hover,
.alert .close:focus {
    color: var(--text-primary);
    background: rgba(var(--alert-rgb), 0.18);
}
