@layer components {
  /* ── Base notice — works inline (auth pages, edit pages) and in toasts ── */

  .notice {
    --app-notice-accent: var(--app-muted-color);
    position: relative;
    display: flex;
    align-items: center;
    gap: calc(var(--app-spacing) * 0.625);
    padding: calc(var(--app-spacing) * 0.75) calc(var(--app-spacing) * 0.875);
    background: var(--app-card-background-color);
    border: 1px solid var(--app-muted-border-color);
    border-radius: calc(var(--app-border-radius) * 1.1);
    color: var(--app-color);
    font-size: var(--text-sm);
    line-height: var(--leading-snug);
    margin-bottom: var(--app-spacing);
    overflow: hidden;
  }

  /* Auto-injected variant icon for notices that don't carry an explicit
     .notice-icon child (= every inline use site). Toasts emit the icon
     in markup so they opt out via :has(). */
  .notice:not(:has(> .notice-icon))::before {
    content: "";
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--app-notice-accent) 16%, transparent);
    color: var(--app-notice-accent);
    font-family: "Bootstrap-icons";
    font-size: var(--text-base);
    font-weight: var(--font-regular);
    line-height: var(--leading-none);
  }

  .notice[data-variant=success]:not(:has(> .notice-icon))::before { content: "\f26a"; }
  .notice[data-variant=info]:not(:has(> .notice-icon))::before    { content: "\f430"; }
  .notice[data-variant=warning]:not(:has(> .notice-icon))::before { content: "\f33a"; }
  .notice[data-variant=error]:not(:has(> .notice-icon))::before   { content: "\f626"; }

  /* Explicit icon span (used by toasts) — same look as the ::before pseudo. */
  .notice .notice-icon {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--app-notice-accent) 16%, transparent);
    color: var(--app-notice-accent);
    font-size: var(--text-base);
  }

  /* Message content slot. Inline notices without an explicit wrapper still
     work because flex layout picks up the next direct child as content. */
  .notice .notice-content {
    flex: 1 1 auto;
    color: var(--app-color);
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .notice ul {
    margin: 0;
    padding-left: 0;
    list-style: none;
    flex: 1 1 auto;
    min-width: 0;
  }

  .notice ul li {
    list-style: none;
    margin: 0;
  }

  .notice ul li + li {
    margin-top: calc(var(--app-spacing) * 0.25);
  }

  .notice p {
    margin: 0;
    flex: 1 1 auto;
    min-width: 0;
  }

  /* Variant accent — drives the icon-pill color. Text stays neutral. */
  .notice[data-variant=success] { --app-notice-accent: var(--app-notice-success-color); }
  .notice[data-variant=warning] { --app-notice-accent: var(--app-notice-warning-color); }
  .notice[data-variant=info]    { --app-notice-accent: var(--app-notice-info-color); }
  .notice[data-variant=error]   { --app-notice-accent: var(--app-notice-error-color); }

  /* ── Toast stack: fixed top-right overlay for ephemeral notifications ── */

  .app-toast-stack {
    position: fixed;
    top: calc(var(--app-spacing) * 1.5);
    right: calc(var(--app-spacing) * 1.5);
    z-index: 1100;
    display: flex;
    flex-direction: column;
    gap: calc(var(--app-spacing) * 0.5);
    width: 400px;
    max-width: calc(100vw - var(--app-spacing) * 3);
    pointer-events: none;
  }

  .app-toast-stack:empty {
    display: none;
  }

  /* In admin layout: offset below topbar */
  .app-container ~ .app-toast-stack,
  body:has(.app-container) .app-toast-stack {
    top: calc(52px + var(--app-spacing));
  }

  @media (max-width: 576px) {
    .app-toast-stack {
      top: calc(var(--app-spacing) * 1);
      right: calc(var(--app-spacing) * 1);
      left: calc(var(--app-spacing) * 1);
      width: auto;
    }

    body:has(.app-container) .app-toast-stack {
      top: calc(52px + var(--app-spacing) * 0.5);
      right: calc(var(--app-spacing) * 0.5);
      left: calc(var(--app-spacing) * 0.5);
    }
  }

  /* Toast-only enhancements on top of the base .notice. */
  .app-toast-stack .notice {
    margin: 0;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.06);
    pointer-events: auto;
    animation: toast-slide-in 250ms ease-out;
  }

  .app-toast-stack .notice.toast-dismissing {
    animation: toast-slide-out 200ms ease-in forwards;
  }

  @keyframes toast-slide-in {
    from { opacity: 0; transform: translateX(20px); }
    to   { opacity: 1; transform: translateX(0); }
  }

  @keyframes toast-slide-out {
    from { opacity: 1; transform: translateX(0); }
    to   { opacity: 0; transform: translateX(20px); }
  }

  @media (prefers-reduced-motion: reduce) {
    .app-toast-stack .notice,
    .app-toast-stack .notice.toast-dismissing {
      animation: none;
    }
  }

  /* ── Progress bar timer (toast only) ─────────────────────────────────── */

  .app-toast-stack .notice.flash-timed::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    height: 2px;
    width: 100%;
    background: var(--app-notice-accent);
    transform-origin: left;
    transform: scaleX(0);
    animation: flash-progress var(--flash-timeout, 4000ms) linear forwards;
    opacity: 0.6;
  }

  .app-toast-stack .notice.flash-timed:hover::after {
    animation-play-state: paused;
  }

  @keyframes flash-progress {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
  }

  @media (prefers-reduced-motion: reduce) {
    .app-toast-stack .notice.flash-timed::after {
      animation: none;
    }
  }

  /* ── Dismiss button (toast only) ─────────────────────────────────────── */

  .app-toast-stack .notice .notice-dismiss-form {
    margin: 0;
    flex-shrink: 0;
  }

  .app-toast-stack .notice .notice-dismiss {
    border: none !important;
    background: transparent;
    color: var(--app-muted-color);
    opacity: 0.6;
    cursor: pointer;
    padding: 4px 6px;
    line-height: var(--leading-none);
    flex-shrink: 0;
    border-radius: 6px;
    transition: opacity 120ms ease, background-color 120ms ease;
  }

  .app-toast-stack .notice .notice-dismiss:hover,
  .app-toast-stack .notice .notice-dismiss:focus-visible {
    opacity: 1;
    background: color-mix(in srgb, var(--app-color) 8%, transparent);
  }
}
