/* ==========================================================================
   ZULLI TOAST  ·  v1.0
   --------------------------------------------------------------------------
   Two surfaces, bound to your theme:

     light mode  —  ink     #12161C   separates by inverting the page
     dark  mode  —  raised  #232B37   separates by rising above it

   Binding is automatic:
     <html>                     → ink
     <html data-theme="dark">   → raised
     no data-theme at all       → follows prefers-color-scheme

   To force one regardless of theme, set data-toast on any ancestor:
     <html data-toast="raised">
     <div  data-toast="ink">        (works on a subtree too)

   Everything lives in the `zulli-toast` cascade layer, so any unlayered
   rule in your own stylesheet wins without needing !important.

   Reads --radius-lg / --shadow-4 / font stacks from the Zulli UI kit when
   present, and falls back to literals when it isn't. Safe standalone.
   ========================================================================== */

@layer zulli-toast {

  /* ------------------------------------------------------------------
     1 · GEOMETRY — ground-independent, set once
     ------------------------------------------------------------------ */
  :root{
    --zt-width:380px;
    --zt-gap:10px;
    --zt-pad-y:17px;
    --zt-pad-x:14px;
    --zt-accent-gap:8px;           /* space above AND below the bottom accent bar / lifespan rail */
    --zt-edge:16px;
    --zt-radius:var(--radius-lg, 6px);
    --zt-max:3;                    /* read by JS, not by CSS */

    --zt-sans:var(--sans, "DM Sans", system-ui, -apple-system, "Segoe UI", sans-serif);
    --zt-mono:var(--mono, "DM Mono", ui-monospace, "SF Mono", Menlo, monospace);

    --zt-dur-in:260ms;
    --zt-dur-out:180ms;
    --zt-ease-out:cubic-bezier(.22,.61,.36,1);
    --zt-ease-exit:cubic-bezier(.4,0,1,1);

    --zt-z:var(--z-toast, 700);
  }

  /* ------------------------------------------------------------------
     2 · SURFACES
     Each carries its own text ramp AND its own role accents, because a
     colour tuned to clear 4.5:1 on #12161C does not clear it on #232B37
     by the same margin — and would not clear it at all on white.
     ------------------------------------------------------------------ */

  /* -- ink · light mode default -- */
  :root,
  [data-theme="light"]{
    --zt-bg:#12161C;
    --zt-border:transparent;
    --zt-peek:#1B222C;
    --zt-shadow:var(--shadow-4, 0 24px 56px -16px rgba(18,22,28,.22), 0 4px 12px -4px rgba(18,22,28,.08));

    --zt-fg-1:#F2F5F9;                    /* title      */
    --zt-fg-2:#A7B1C1;                    /* body       */
    --zt-fg-3:#7E8CA3;                    /* meta, close */
    --zt-line:rgba(255,255,255,.13);
    --zt-fill:rgba(255,255,255,.07);
    --zt-fill-2:rgba(255,255,255,.14);

    --zt-success:#6BC49C;
    --zt-danger:#E2907A;
    --zt-warning:#E3B96B;
    --zt-info:#89B4F8;
    --zt-neutral:#7E8CA3;

    --zt-media:#243040;                   /* avatar / thumbnail ground */
    --zt-media-fg:#B9CBE6;
  }

  /* -- raised · picked up from the OS only when the app hasn't declared a theme -- */
  @media (prefers-color-scheme: dark){
    :root:not([data-theme]){
      --zt-bg:#232B37;
      --zt-border:rgba(255,255,255,.11);
      --zt-peek:#2C3543;
      --zt-shadow:0 26px 60px -18px rgba(0,0,0,.86), 0 3px 10px -3px rgba(0,0,0,.60);
      --zt-fg-2:#B3BCC9;
      --zt-fg-3:#8A94A4;
      --zt-line:rgba(255,255,255,.15);
      --zt-fill:rgba(255,255,255,.08);
      --zt-fill-2:rgba(255,255,255,.16);
      --zt-media:#333E4E;
      --zt-media-fg:#C4D2E6;
    }
  }

  /* -- raised · dark mode default -- */
  [data-theme="dark"]{
    --zt-bg:#232B37;
    --zt-border:rgba(255,255,255,.11);
    --zt-peek:#2C3543;
    --zt-shadow:0 26px 60px -18px rgba(0,0,0,.86), 0 3px 10px -3px rgba(0,0,0,.60);
    --zt-fg-2:#B3BCC9;
    --zt-fg-3:#8A94A4;
    --zt-line:rgba(255,255,255,.15);
    --zt-fill:rgba(255,255,255,.08);
    --zt-fill-2:rgba(255,255,255,.16);
    --zt-media:#333E4E;
    --zt-media-fg:#C4D2E6;
  }

  /* -- explicit override. The doubled attribute lifts specificity to 0,2,0
        so it beats [data-theme="dark"] no matter the source order. -- */
  [data-toast="ink"][data-toast]{
    --zt-bg:#12161C;
    --zt-border:transparent;
    --zt-peek:#1B222C;
    --zt-shadow:var(--shadow-4, 0 24px 56px -16px rgba(18,22,28,.22), 0 4px 12px -4px rgba(18,22,28,.08));
    --zt-fg-2:#A7B1C1;
    --zt-fg-3:#7E8CA3;
    --zt-line:rgba(255,255,255,.13);
    --zt-fill:rgba(255,255,255,.07);
    --zt-fill-2:rgba(255,255,255,.14);
    --zt-media:#243040;
    --zt-media-fg:#B9CBE6;
  }
  [data-toast="raised"][data-toast]{
    --zt-bg:#232B37;
    --zt-border:rgba(255,255,255,.11);
    --zt-peek:#2C3543;
    --zt-shadow:0 26px 60px -18px rgba(0,0,0,.86), 0 3px 10px -3px rgba(0,0,0,.60);
    --zt-fg-2:#B3BCC9;
    --zt-fg-3:#8A94A4;
    --zt-line:rgba(255,255,255,.15);
    --zt-fill:rgba(255,255,255,.08);
    --zt-fill-2:rgba(255,255,255,.16);
    --zt-media:#333E4E;
    --zt-media-fg:#C4D2E6;
  }

  /* ------------------------------------------------------------------
     3 · STACK
     ------------------------------------------------------------------ */
  .zt-stack{
    position:fixed;
    z-index:var(--zt-z);
    display:grid;
    gap:var(--zt-gap);
    width:min(var(--zt-width), calc(100vw - var(--zt-edge) * 2));
    grid-template-columns:minmax(0,1fr);
    pointer-events:none;
    margin:0;
    padding:0;
    list-style:none;
  }
  .zt-stack > *{ pointer-events:auto; }
  /* an exiting toast is lifted out of the grid by the engine so the ones
     below can close the gap while it finishes fading */
  .zt-stack{ isolation:isolate; }

  .zt-stack[data-pos="bottom-right"]{
    inset-block-end:calc(var(--zt-edge) + env(safe-area-inset-bottom, 0px));
    inset-inline-end:var(--zt-edge);
  }
  .zt-stack[data-pos="bottom-left"]{
    inset-block-end:calc(var(--zt-edge) + env(safe-area-inset-bottom, 0px));
    inset-inline-start:var(--zt-edge);
  }
  .zt-stack[data-pos="bottom-center"]{
    inset-block-end:calc(var(--zt-edge) + env(safe-area-inset-bottom, 0px));
    inset-inline-start:50%;
    translate:-50% 0;
  }
  .zt-stack[data-pos="top-right"]{
    inset-block-start:calc(var(--zt-edge) + env(safe-area-inset-top, 0px));
    inset-inline-end:var(--zt-edge);
  }
  .zt-stack[data-pos="top-left"]{
    inset-block-start:calc(var(--zt-edge) + env(safe-area-inset-top, 0px));
    inset-inline-start:var(--zt-edge);
  }
  .zt-stack[data-pos="top-center"]{
    inset-block-start:calc(var(--zt-edge) + env(safe-area-inset-top, 0px));
    inset-inline-start:50%;
    translate:-50% 0;
  }

  /* Phone: always top. A bottom-anchored toast collides with a sticky
     action bar and with the home indicator. */
  @media (max-width: 620px){
    .zt-stack{
      inset:calc(var(--zt-edge) + env(safe-area-inset-top, 0px)) var(--zt-edge) auto var(--zt-edge) !important;
      width:auto;
      translate:none !important;
    }
  }

  .zt-more{
    justify-self:center;
    font-family:var(--zt-mono);
    font-size:11px;
    letter-spacing:.06em;
    background:var(--zt-bg);
    color:var(--zt-fg-3);
    border:1px solid var(--zt-line);
    padding:5px 11px;
    border-radius:999px;
    box-shadow:var(--zt-shadow);
  }

  /* ------------------------------------------------------------------
     4 · TOAST
     ------------------------------------------------------------------ */
  .zt{
    display:grid;
    grid-template-columns:auto minmax(0,1fr) auto;
    gap:11px;
    align-items:start;
    position:relative;
    overflow:hidden;
    box-sizing:border-box;
    max-width:100%;
    padding:var(--zt-pad-y) var(--zt-pad-x);
    border:1px solid var(--zt-border);
    border-radius:var(--zt-radius);
    background:var(--zt-bg);
    color:var(--zt-fg-2);
    box-shadow:var(--zt-shadow);
    font-family:var(--zt-sans);
    font-size:12.5px;
    line-height:1.5;
    animation:zt-in var(--zt-dur-in) var(--zt-ease-out) both;
  }
  .zt *,
  .zt *::before,
  .zt *::after{ box-sizing:border-box; }

  .zt-stack[data-pos^="top"] .zt{ animation-name:zt-in-top; }

  /* The entrance plays once. The engine flags a toast as entered, and from
     then on it can be reordered in the DOM without replaying the animation —
     re-attaching a node restarts CSS animations, and a stack that re-fades
     every toast each time a new one arrives is the result. */
  .zt[data-entered]:not([data-leaving]){ animation:none; }

  .zt[data-leaving]{
    animation:zt-out var(--zt-dur-out) var(--zt-ease-exit) both;
    pointer-events:none;
    z-index:0;
  }

  @keyframes zt-in{ from{opacity:0; transform:translateY(14px) scale(.97)} to{opacity:1; transform:none} }
  @keyframes zt-in-top{ from{opacity:0; transform:translateY(-14px) scale(.97)} to{opacity:1; transform:none} }
  @keyframes zt-out{ to{opacity:0; transform:translateX(18%) scale(.97)} }

  /* single-line: no body copy */
  .zt[data-compact]{ align-items:center; }
  .zt[data-compact] .zt-icon,
  .zt[data-compact] .zt-aside{ margin-block-start:0; }
  .zt[data-compact] .zt-title{ margin-block-end:0; }

  /* ------------------------------------------------------------------
     5 · ROLES
     One --zt-accent per role. The icon and the bottom bar both read it,
     so there is no separate coloured rail to state the role twice.
     ------------------------------------------------------------------ */
  .zt[data-role="success"]{ --zt-accent:var(--zt-success); }
  .zt[data-role="danger"] { --zt-accent:var(--zt-danger); }
  .zt[data-role="warning"]{ --zt-accent:var(--zt-warning); }
  .zt[data-role="info"]   { --zt-accent:var(--zt-info); }
  .zt[data-role="neutral"]{ --zt-accent:var(--zt-neutral); }

  /* static accent on the bottom edge — the state for persistent toasts.
     Inset from the true edge so it reads as a detail sitting inside the
     toast's padding, not as the toast having no bottom padding at all. */
  .zt::before{
    content:"";
    position:absolute;
    inset-block-end:var(--zt-accent-gap, 6px);
    inset-inline:0;
    height:2px;
    background:var(--zt-accent);
  }

  /* ------------------------------------------------------------------
     6 · PARTS
     ------------------------------------------------------------------ */
  .zt-icon{
    width:16px; height:16px;
    margin-block-start:2px;
    flex:none;
    color:var(--zt-accent);
    stroke-width:1.7;
  }

  .zt-body{ min-width:0; }
  .zt-title{
    display:block;
    margin-block-end:2px;
    font-size:13.5px;
    font-weight:600;
    letter-spacing:-.004em;
    color:var(--zt-fg-1);
  }
  .zt-text{
    margin:0;
    color:var(--zt-fg-2);
    overflow-wrap:anywhere;
  }
  .zt-meta{
    display:block;
    margin-block-start:4px;
    font-family:var(--zt-mono);
    font-size:11px;
    letter-spacing:.03em;
    font-variant-numeric:tabular-nums;
    color:var(--zt-fg-3);
  }
  .zt-num{
    font-family:var(--zt-mono);
    font-variant-numeric:tabular-nums;
    font-weight:500;
    color:var(--zt-fg-1);
  }

  .zt-aside{
    display:flex;
    align-items:center;
    gap:2px;
    flex:none;
    margin-block-start:-2px;
  }

  .zt-action{
    appearance:none;
    border:0;
    background:transparent;
    cursor:pointer;
    flex:none;
    padding:5px 8px;
    border-radius:4px;
    white-space:nowrap;
    font-family:var(--zt-sans);
    font-size:12.5px;
    font-weight:600;
    color:var(--zt-info);
    transition:background 120ms var(--zt-ease-out), color 120ms var(--zt-ease-out);
  }
  .zt-action:hover{ background:var(--zt-fill); }
  .zt-action:focus-visible{ outline:2px solid var(--zt-info); outline-offset:1px; }
  .zt-action[data-danger]{ color:var(--zt-danger); }
  .zt-action[data-danger]:hover{ background:var(--zt-fill-2); }
  .zt-action[data-danger]:focus-visible{ outline-color:var(--zt-danger); }

  /* two or more actions drop below the body */
  .zt-actions{
    display:flex;
    flex-wrap:wrap;
    gap:6px;
    margin-block-start:9px;
  }
  .zt-actions .zt-action{
    padding:6px 9px;
    font-size:12px;
    background:var(--zt-fill);
    border:1px solid var(--zt-line);
  }
  .zt-actions .zt-action:hover{ background:var(--zt-fill-2); }

  .zt-close{
    appearance:none;
    border:0;
    background:transparent;
    cursor:pointer;
    flex:none;
    width:26px; height:26px;
    border-radius:4px;
    display:grid;
    place-items:center;
    color:var(--zt-fg-3);
    transition:background 120ms var(--zt-ease-out), color 120ms var(--zt-ease-out);
  }
  .zt-close:hover{ background:var(--zt-fill); color:var(--zt-fg-1); }
  .zt-close:focus-visible{ outline:2px solid var(--zt-fg-3); outline-offset:1px; }
  .zt-close svg{ width:12px; height:12px; stroke-width:1.9; }

  .zt-count{
    font-family:var(--zt-mono);
    font-size:10.5px;
    font-weight:500;
    font-variant-numeric:tabular-nums;
    background:var(--zt-fill-2);
    color:var(--zt-fg-1);
    padding:3px 7px;
    border-radius:999px;
  }

  /* -- media slots -- */
  .zt-avatar{
    width:30px; height:30px;
    flex:none;
    border-radius:50%;
    display:grid;
    place-items:center;
    overflow:hidden;
    background:var(--zt-media);
    color:var(--zt-media-fg);
    font-family:var(--zt-sans);
    font-size:11px;
    font-weight:600;
  }
  .zt-avatar img{ width:100%; height:100%; object-fit:cover; }
  .zt-thumb{
    width:34px; height:34px;
    flex:none;
    border-radius:4px;
    overflow:hidden;
    background:var(--zt-media);
  }
  .zt-thumb img{ width:100%; height:100%; object-fit:cover; display:block; }

  /* -- progress -- */
  .zt-progress{
    height:3px;
    margin-block-start:9px;
    border-radius:999px;
    overflow:hidden;
    background:var(--zt-fill);
  }
  .zt-progress > i{
    display:block;
    height:100%;
    width:0;
    border-radius:inherit;
    background:var(--zt-accent);
    transition:width 260ms var(--zt-ease-out);
  }
  .zt-progress[data-indeterminate] > i{
    width:35%;
    animation:zt-slide 1.3s var(--zt-ease-out) infinite;
  }
  @keyframes zt-slide{ 0%{transform:translateX(-105%)} 100%{transform:translateX(320%)} }

  /* -- lifespan. Opaque track covers ::before, so the accent visibly
        drains away as the timer runs. -- */
  .zt-life{
    position:absolute;
    inset-block-end:var(--zt-accent-gap, 6px);
    inset-inline:0;
    height:2px;
    background:var(--zt-bg);
  }
  .zt-life > i{
    display:block;
    height:100%;
    background:var(--zt-accent);
    transform-origin:left center;
    animation:zt-drain linear forwards;
  }
  @keyframes zt-drain{ from{transform:scaleX(1)} to{transform:scaleX(0)} }

  /* -- countdown ring -- */
  .zt-ring{ width:26px; height:26px; flex:none; }
  .zt-ring circle{ fill:none; stroke-width:2.5; }
  .zt-ring .zt-ring-bg{ stroke:var(--zt-fill); }
  .zt-ring .zt-ring-fg{
    stroke:var(--zt-accent);
    stroke-linecap:round;
    stroke-dasharray:69.1;
    transform:rotate(-90deg);
    transform-origin:center;
    animation:zt-ring linear forwards;
  }
  @keyframes zt-ring{ from{stroke-dashoffset:0} to{stroke-dashoffset:69.1} }

  /* -- spinner -- */
  .zt-spinner{
    width:15px; height:15px;
    flex:none;
    margin-block-start:2px;
    border-radius:50%;
    border:2px solid var(--zt-fill-2);
    border-top-color:var(--zt-accent);
    animation:zt-spin 620ms linear infinite;
  }
  @keyframes zt-spin{ to{transform:rotate(360deg)} }

  /* -- grouped: a sheet peeking out from behind -- */
  .zt[data-grouped]{ margin-block-end:6px; }
  .zt[data-grouped]::after{
    content:"";
    position:absolute;
    inset-inline:8px;
    inset-block-end:-5px;
    height:6px;
    z-index:-1;
    background:var(--zt-peek);
    border-radius:0 0 var(--zt-radius) var(--zt-radius);
  }

  /* ------------------------------------------------------------------
     7 · TOUCH — hit area grows to 44px, visual size unchanged
     ------------------------------------------------------------------ */
  @media (pointer: coarse){
    .zt-action,
    .zt-close{ position:relative; }
    .zt-action::before,
    .zt-close::before{
      content:"";
      position:absolute;
      top:50%; left:50%;
      transform:translate(-50%,-50%);
      width:max(100%, 44px);
      height:max(100%, 44px);
    }
    /* siblings sit flush, so these widen the real box instead —
       overlapping pseudo targets would fire the wrong control */
    .zt-actions .zt-action{ min-height:40px; }
    .zt-actions .zt-action::before{ display:none; }
  }

  /* ------------------------------------------------------------------
     8 · REDUCED MOTION — neutralise the animation, keep the timer
     ------------------------------------------------------------------ */
  @media (prefers-reduced-motion: reduce){
    .zt,
    .zt[data-leaving]{ animation-duration:.01ms; }
    .zt-life > i,
    .zt-ring .zt-ring-fg,
    .zt-spinner{ animation:none; }
    .zt-life > i{ transform:scaleX(1); }
    .zt-progress[data-indeterminate] > i{ width:100%; animation:none; transform:none; }
    .zt-progress > i{ transition:none; }
  }

  /* ------------------------------------------------------------------
     9 · PRINT — a toast is never part of the document
     ------------------------------------------------------------------ */
  @media print{
    .zt-stack{ display:none !important; }
  }

  /* ------------------------------------------------------------------
     10 · HIGH CONTRAST
     ------------------------------------------------------------------ */
  @media (forced-colors: active){
    .zt{ border:1px solid CanvasText; }
    .zt::before,
    .zt-life{ forced-color-adjust:none; }
  }
}
