/* TLC Feedback — §18. Veil + toast.
   Fills read Bootstrap's themed tokens (brand values live in bs-theme.css).
   States: .is-success / .is-danger / .is-warning
   Legacy aliases: .is-go == .is-success, .is-warn == .is-warning (SWC names).

   ⚠ THAT LIST IS CLOSED, AND AN UNKNOWN STATE PAINTS AS SUCCESS.
   The base rule seeds FOUR tokens with the SUCCESS green — --veil-fill,
   --veil-stroke, and the --tlc-toast-fill / --tlc-toast-stroke fallbacks — so a
   bare .tlc-veil can be the busy/spinner state (SWC text-edit.js:951 relies on
   this; Craig, 2026-08-19: "once the green modal pops up"). CSS cannot tell a
   deliberately bare element from one wearing a class no rule ever matched, so
   .is-error / .is-fail / .is-info / .is-saved — anything not in the list above —
   silently renders as SUCCESS. The state that means "your work did not save"
   looks exactly like the one that means it did. Nothing throws.
   The 2026-08-20 Mongoose sync made this LOUDER, not safer: the stroke is now
   the same hue at FULL opacity and is, by design, the one place the true color
   shows undiluted — so a mislabeled failure now asserts success harder.
   Both known callers BUILD the class by concatenation — showVeil() does
   "tlc-veil is-" + kind, toast() does " is-" + kind — so adding a fourth kind is
   one word of JS away from that failure.
   Adding a state = add the rule HERE first, then the caller. Never the reverse.
   AND A STATE IS TWO TOKENS NOW, NOT ONE. Every state sets fill AND stroke in
   the same rule; set only the fill and the panel comes up in the new color
   ringed in the old green, which reads as a rendering glitch rather than the
   missing declaration it is. Treat the pair as the unit.
   Verify by probe, not by eye: flip a live node through every kind and assert
   each computes a DIFFERENT fill AND stroke than the resting one (CC's
   ?states=1 pattern, bus #261). See 00_resources/treepl-gotchas.md.

   White ink throughout — these are ops-only surfaces (the bright family).
   No .is-green / .is-yellow variant until a public page needs one.
   Contrast fails AA on success (2.75:1) and warning (1.40:1). Deliberate.
   Public pages use btn-green / btn-yellow instead. Do not "fix" to dark ink.

   Hard-won geometry from SWC / MongooseSports Review Board — keep verbatim:
   width:min(350px,100%) NOT 94vw
   phone padding AFTER the unmediated rule
   blanket [hidden]{display:none!important}

   ✔ MONGOOSE SYNC LANDED 2026-08-20, on Craig — the divergence note that stood
   here is discharged. The Review Board is where this component came from, it
   finished shaping, and this file now matches what it established. Three
   changes, and the ORDER is why they work; do not reintroduce any one of them
   on its own.

   1. THE FILL IS .7, NOT .82/.88. Craig: "opacity should be changed to 0.7 for
      all of these states popup overlays." This only reads correctly AFTER (2)
      and (3). At .82 over rgba(10,12,14,.42) plus a 3px blur the color was
      already carrying black twice over; dropping to .7 on a dull fill with a
      white rim would have read as mud.
   2. THE BORDER IS THE SAME COLOR AT FULL OPACITY — `1px solid var(--veil-stroke)`.
      Craig: "I also think there's a weird white border on these. I would love a
      border with 100% opacity in it's same color." The old
      `rgba(255,255,255,.30)` put a lighter, DIFFERENT-HUE line around every
      panel, which is both the "weird white border" and the thing that made the
      fill look grayer beside it. The border is now the one place the true color
      shows undiluted, so the FILL only has to carry the text — which is what
      buys the 30% in (1).
   3. THE SHADOW IS 0 2px 10px rgba(0,0,0,.28), NOT 0 26px 70px rgba(0,0,0,.42).
      A 70px black bloom under a hard, fully opaque, saturated border reads as
      fringing — two different edges half a pixel apart. The dark scrim and the
      backdrop blur were already doing the separating.

   Padding is 40px 50px on EVERY state, not just the held one (Craig: "update
   padding on all, not just this one"), and 50px clears a close mark on its own.

   THE STATE LIST IS UNCHANGED and warning moved with the other two — Craig named
   all three: "the brighter established danger, warning and success colors". A
   state left on the old grammar is the drift this sync exists to end.

   Nothing here reads a --swcE-* token. Type: --ButtonFont. */

/* ── veil ─────────────────────────────────────────────────────────── */
.tlc-veil {
  position: fixed; inset: 0; z-index: 2147483650;
  display: grid; place-items: center; padding: 24px;
  opacity: 0; transition: opacity .22s cubic-bezier(.22, .61, .36, 1);
  background: rgba(10, 12, 14, .42);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  --mgo-size: clamp(20px, min(3.6vw, 2.5vh), 22px);
  --mgo-bump: 0px;
  --veil-fill: rgba(var(--bs-success-rgb, 0, 181, 43), .7);
  --veil-stroke: rgb(var(--bs-success-rgb, 0, 181, 43));
  --veil-ink: #fff;
  --veil-ink2: rgba(255, 255, 255, .92);
}
.tlc-veil.is-success,
.tlc-veil.is-go { --veil-fill: rgba(var(--bs-success-rgb, 0, 181, 43), .7);
                  --veil-stroke: rgb(var(--bs-success-rgb, 0, 181, 43)); }
.tlc-veil.is-danger { --veil-fill: rgba(var(--bs-danger-rgb, 230, 0, 0), .7);
                      --veil-stroke: rgb(var(--bs-danger-rgb, 230, 0, 0)); }
.tlc-veil.is-warning,
.tlc-veil.is-warn { --veil-fill: rgba(var(--bs-warning-rgb, 255, 215, 0), .7);
                    --veil-stroke: rgb(var(--bs-warning-rgb, 255, 215, 0)); }
.tlc-veil.is-in { opacity: 1; }
.tlc-veil [hidden],
.tlc-toast [hidden],
.tlc-toaster [hidden] { display: none !important; }
.tlc-veil-box {
  display: flex; flex-direction: column; align-items: center; gap: 0;
  width: min(350px, 100%); padding: 40px 50px;
  border-radius: 18px; text-align: center;
  background: var(--veil-fill); border: 1px solid var(--veil-stroke);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .28);
  overflow-wrap: anywhere;
  transform: scale(.965); transition: transform .22s cubic-bezier(.22, .61, .36, 1);
}
.tlc-veil.is-in .tlc-veil-box { transform: scale(1); }
/* 350px IS A WIDTH FOR "SAVED". An error carries a filename AND a reason, and
   filenames and URLs have no space to break at — so a long token runs straight
   through the padding and out of the box. `overflow-wrap:anywhere` above is the
   half that actually stops the overflow; widening alone only moves it. */
.tlc-veil-box.is-wide { width: min(760px, 100%); }
@media (max-width: 560px) {
  .tlc-veil { padding: 14px; }
  .tlc-veil-box { padding: 26px 24px; }
}
.tlc-veil h2 {
  margin: clamp(15px, 2.2vh, 24px) 0 0; color: var(--veil-ink);
  font-family: var(--ButtonFont, inherit); font-weight: 900;
  font-size: calc(var(--mgo-size) + var(--mgo-bump)); line-height: 1.15;
  letter-spacing: .04em; text-transform: uppercase;
}
.tlc-veil p {
  margin: 14px 0 0; color: var(--veil-ink2);
  font-family: var(--ButtonFont, inherit); font-weight: 300;
  font-size: var(--mgo-size); line-height: 1.15;
}
.tlc-veil-acts {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: stretch;
  gap: 10px; margin: 26px 0 4px;
}
.tlc-veil-acts > * { flex: 1 1 0; min-width: 0; }
.tlc-veil-ok {
  margin: 0; padding: 12px 26px;
  min-width: 140px;
  font-family: var(--ButtonFont, inherit); font-size: 14px; letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--veil-ink); background: rgba(255, 255, 255, .16);
  border: 1px solid rgba(255, 255, 255, .55); border-radius: var(--RadiusBrand, 6px);
  cursor: pointer; transition: background .2s ease;
}
.tlc-veil-ok:hover { background: rgba(255, 255, 255, .28); }
.tlc-veil-ok:focus-visible { outline: 2px solid var(--veil-ink); outline-offset: 2px; }
.tlc-veil-tell {
  margin: 0; padding: 12px 22px;
  min-width: 140px;
  font-family: var(--ButtonFont, inherit); font-size: 14px; letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--veil-ink2); background: transparent;
  border: 1px solid rgba(255, 255, 255, .30); border-radius: var(--RadiusBrand, 6px);
  cursor: pointer; transition: background .2s ease, border-color .2s ease, color .2s ease;
}
.tlc-veil-tell:hover { background: rgba(255, 255, 255, .14); border-color: rgba(255, 255, 255, .55); }
.tlc-veil-tell:focus-visible { outline: 2px solid var(--veil-ink); outline-offset: 2px; }
.tlc-veil-tell.is-sent {
  color: var(--veil-ink2); border-color: rgba(255, 255, 255, .18);
  background: transparent; cursor: default; letter-spacing: .10em;
}
.tlc-veil-tell.is-failed { border-color: rgba(255, 255, 255, .70); color: var(--veil-ink); }

.tlc-veil .preloader-wrapper {
  position: relative; display: inline-block; width: 54.4px; height: 54.4px;
  font-size: 0; animation: tlcFb-rotate 1568ms linear infinite;
}
.tlc-veil .preloader-wrapper.crazy { animation-duration: 333ms; }
.tlc-veil .spinner-layer {
  position: absolute; width: 100%; height: 100%; opacity: 1; border-color: #fff;
  animation: tlcFb-fill 5332ms cubic-bezier(.4, 0, .2, 1) infinite both;
}
.tlc-veil .gap-patch {
  position: absolute; top: 0; left: 45%; width: 10%; height: 100%;
  overflow: hidden; border-color: inherit;
}
.tlc-veil .gap-patch .circle { left: -450%; width: 1000%; }
.tlc-veil .circle-clipper {
  position: relative; display: inline-block; width: 50%; height: 100%;
  overflow: hidden; border-color: inherit;
}
.tlc-veil .circle-clipper .circle {
  position: absolute; top: 0; right: 0; bottom: 0; width: 200%; height: 100%;
  border-color: inherit; border-style: solid; border-width: 3.6px;
  border-bottom-color: transparent; border-radius: 50%;
}
.tlc-veil .circle-clipper.left .circle {
  left: 0; border-right-color: transparent;
  transform: rotate(129deg); animation: tlcFb-left 1333ms cubic-bezier(.4, 0, .2, 1) infinite both;
}
.tlc-veil .circle-clipper.right .circle {
  left: -100%; border-left-color: transparent;
  transform: rotate(-129deg); animation: tlcFb-right 1333ms cubic-bezier(.4, 0, .2, 1) infinite both;
}
@keyframes tlcFb-rotate { to { transform: rotate(360deg); } }
@keyframes tlcFb-fill {
  12.5% { transform: rotate(135deg); } 25% { transform: rotate(270deg); }
  37.5% { transform: rotate(405deg); } 50% { transform: rotate(540deg); }
  62.5% { transform: rotate(675deg); } 75% { transform: rotate(810deg); }
  87.5% { transform: rotate(945deg); } to { transform: rotate(1080deg); }
}
@keyframes tlcFb-left {
  from { transform: rotate(130deg); } 50% { transform: rotate(-5deg); } to { transform: rotate(130deg); }
}
@keyframes tlcFb-right {
  from { transform: rotate(-130deg); } 50% { transform: rotate(5deg); } to { transform: rotate(-130deg); }
}
@media (prefers-reduced-motion: reduce) {
  .tlc-veil, .tlc-veil-box { transition: none; }
  .tlc-veil .preloader-wrapper, .tlc-veil .spinner-layer,
  .tlc-veil .circle-clipper .circle { animation-duration: 4s; }
}

/* ── toast ────────────────────────────────────────────────────────── */
.tlc-toaster {
  position: fixed; left: 16px; z-index: 2147483000;
  bottom: calc(var(--tlc-dock, 0px) + 16px);
  display: flex; flex-direction: column-reverse; align-items: flex-start; gap: 10px;
  pointer-events: none;
}
.tlc-toaster > * { pointer-events: auto; }

.tlc-toast {
  padding: 9px 15px;
  font-family: var(--ButtonFont, inherit); font-size: 12px; line-height: 1.2;
  letter-spacing: .10em; text-transform: uppercase;
  color: #fff;
  background: var(--tlc-toast-fill, rgba(var(--bs-success-rgb, 0, 181, 43), .7));
  backdrop-filter: blur(8px) saturate(1.15);
  -webkit-backdrop-filter: blur(8px) saturate(1.15);
  /* Same grammar as the veil — .7 fill, same-color stroke at FULL opacity, and
     the tight shadow. The PILL KEEPS ITS OWN GEOMETRY: 9px 15px and radius 12,
     because it is a corner pill, not a modal. Mongoose has no pill; only the
     color grammar syncs. */
  border: 1px solid var(--tlc-toast-stroke, rgb(var(--bs-success-rgb, 0, 181, 43)));
  border-radius: 12px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .28);
  transition: background .2s ease, border-color .2s ease;
}
button.tlc-toast { cursor: pointer; }
body > .tlc-toast {
  position: fixed; left: 16px; bottom: calc(var(--tlc-dock, 0px) + 16px);
  z-index: 2147483000;
}
button.tlc-toast:hover {
  background: rgba(var(--bs-success-rgb, 0, 181, 43), .94);
  /* The hover used to lighten the RIM to rgba(255,255,255,.55). That is the
     white border this sync removed, reappearing on hover only — keep the fill
     lift, keep the stroke the role color. */
  border-color: var(--tlc-toast-stroke, rgb(var(--bs-success-rgb, 0, 181, 43)));
}
button.tlc-toast.is-warning:hover,
button.tlc-toast.is-warn:hover {
  background: rgba(var(--bs-warning-rgb, 255, 215, 0), .96);
}
button.tlc-toast.is-danger:hover {
  background: rgba(var(--bs-danger-rgb, 230, 0, 0), .94);
}
.tlc-toast:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.tlc-toast.is-ghost { opacity: 0; transform: translateY(6px); }
.tlc-toast.is-live { transition: opacity .28s ease, transform .28s ease; }
.tlc-toast.is-success,
.tlc-toast.is-go { --tlc-toast-fill: rgba(var(--bs-success-rgb, 0, 181, 43), .7);
                   --tlc-toast-stroke: rgb(var(--bs-success-rgb, 0, 181, 43)); }
.tlc-toast.is-warning,
.tlc-toast.is-warn { --tlc-toast-fill: rgba(var(--bs-warning-rgb, 255, 215, 0), .7);
                     --tlc-toast-stroke: rgb(var(--bs-warning-rgb, 255, 215, 0)); }
.tlc-toast.is-danger { --tlc-toast-fill: rgba(var(--bs-danger-rgb, 230, 0, 0), .7);
                      --tlc-toast-stroke: rgb(var(--bs-danger-rgb, 230, 0, 0)); }
