/* ==========================================================================
 * SHARED·TOAST (1209) — the confirmation pill.
 *
 * A small dark pill at the foot of the screen that says an action worked,
 * then leaves by itself. One line, past tense ("Name saved", "Email changed"),
 * no button, no icon. Andrew 2026-09-21: "What is our toast? We need these"
 * (DECISIONS-2026-09-14); size ruled 2026-09-22 ("Ok 46") — 15px text, 15px
 * top/bottom + 22px side padding, ≈46px tall, ink-900 ground, cream text,
 * fully rounded — superseding the smaller "A" size drawn the day before.
 *
 * CONFIRMATIONS ONLY. Never an error (errors stay on the page beside the thing
 * that failed), never anything that needs a tap, an undo, or a decision. The
 * app-wide entry point stays window.toast (web/js/util.js) — 22 existing call
 * sites forward to this card's renderer; their MESSAGES are each caller's own
 * discipline, not this card's.
 *
 * THE REGION EXISTS ONCE, IN THE SHELL: <div id="toast" class="tst" role="status">
 * in web/index.html, a direct child of <body> outside #app, so no route render
 * can remove or duplicate it. role="status" makes screen readers announce the
 * text when it changes (polite — it waits, never interrupts). The app's other
 * live values (stepper, amount entry) use the same polite convention.
 *
 * TWO IN A ROW = REPLACE, never queue. A second confirmation re-skins the same
 * pill and restarts the clock. The drawn states (PROFILE-toast-2026-09-21-2x.png)
 * show only ever one pill; a stack would grow upward over the thing she is
 * doing, and a queue would deliver "saved" long after the save. Existing app
 * behaviour (the stub this card replaces) also replaced — nothing changes under
 * the 22 callers.
 *
 * A TOAST BELONGS TO ITS SCREEN (V2 D-TOAST-PERSISTS-ACROSS-ROUTES): a route
 * change dismisses it. The listener lives in toast.render.js with the behaviour.
 * ========================================================================== */

.tst {
  position: fixed;
  /* THE FOOT — the drawn position (PROFILE-toast-2026-09-21-2x.png): a sliver of
   * air above the bottom edge. --tst-clear is MEASURED at show time by the
   * renderer (the --tools-bar-h precedent): when the tab bar is on screen the
   * renderer lifts the pill above it, so it never covers a control she needs
   * (the ruling's own line); with no bar — a drill-in, or the bar away — the
   * pill sits exactly where the drawing puts it. */
  bottom: var(--tst-clear, calc(var(--space-16) + env(safe-area-inset-bottom, 0px)));
  left: 50%;
  transform: translateX(-50%) translateY(var(--dim-12));
  z-index: calc(var(--z-overlay) + 1); /* above everything, incl. a modal scrim — the ruling: never cover a control she needs */
  box-sizing: border-box;
  max-width: calc(100% - var(--dim-32));
  /* THE RULED SIZE (2026-09-22, "Ok 46"): 15px text, 15 + 15 padding, 16px line
   * = 46px tall; 22px sides. The paddings are the founder-ruled one-off — the
   * 4px grid has no 15 or 22, and the ruling is measured against Material 3's
   * own 48dp spec. Line-height 16 (a --dim size: how big the text box is) sets
   * the total; do not "fix" it to a space token or the pill leaves 46. */
  padding: 15px 22px; /* token-exception */
  border-radius: var(--radius-pill);
  background: var(--ink-900);
  color: var(--text-on-dark);
  font-family: var(--font-body);
  /* 15px is the ruled size (2026-09-22, "Ok 46") — the type ladder has no
   * --text-* role at 15, and the ruling is measured, not invented. */
  font-size: var(--size-15); /* token-exception */
  font-weight: var(--weight-500);
  line-height: var(--dim-16);
  text-align: center;
  box-shadow: 0 var(--space-8) var(--space-24) var(--ink-900-a18);
  opacity: 0;
  pointer-events: none;
  /* THE LEAVE — 150ms, the D-422 functional speed. Declared on the BASE (the
   * state a leave arrives at); the enter override sits on .tst-on below. */
  transition: opacity var(--duration-150) var(--ease-standard),
              transform var(--duration-150) var(--ease-standard);
}

/* RESTING / the ENTER destination — 200ms ease-out, the same two-speed rise the
 * tools panel uses. ⚠️ KEEP THE translateX(-50%): the pill is centred by
 * left:50% + a translate, and a transform is ONE property — dropping the -50%
 * here slides it half its own width sideways on every show. */
.tst-on {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  transition: opacity var(--duration-200) var(--ease-out),
              transform var(--duration-200) var(--ease-out);
}

/* ── THE MID-TRANSITION STILLS — the swiperemove `.is-mid` pattern (122): honest
 * frozen points for the mirror page and the library recipe, transition off so a
 * static page can hold them. They are never set by the behaviour — renderToast
 * only ever adds .tst-on. appearing: half risen; leaving: further out and more
 * than half gone. */
.tst.is-enter-mid {
  opacity: .5;
  transform: translateX(-50%) translateY(calc(var(--dim-12) / 2));
  transition: none;
}
.tst.is-leave-mid {
  opacity: .3;
  transform: translateX(-50%) translateY(calc(var(--dim-12) * 0.75));
  transition: none;
}

/* No glide for reduced motion — the pill snaps, same rule as the swipe card. */
@media (prefers-reduced-motion: reduce) {
  .tst,
  .tst-on { transition: none; }
}
