/* static/_shared/slow-action.css
 *
 * The delayed busy veil. Read static/_shared/slow-action.js first: this file
 * only dresses what that driver decides, and the decision that matters (paint
 * nothing at all for the first second) is made there, not here.
 *
 * WHY A SEPARATE FILE RATHER THAN THE EXISTING .loading-overlay FAMILY. That
 * family lives in _shared/agent-base.css, and workspace/base.html does not load
 * agent-base.css. Exactly one workspace page does, the replan hold screen, and
 * it loads it for the spinner. Linking a whole surface's base stylesheet into
 * every workspace page to reach one spinner would bring its page grid, its
 * button states and its textarea styling with it, which is a far larger change
 * than the one being made. The spinner's numbers are copied from
 * .loading-spinner below instead, deliberately and identically, so the two read
 * as the same object to a user who meets both.
 *
 * The other reason they are separate objects: .loading-overlay is fixed to the
 * viewport and covers the whole page. This one covers a region and leaves the
 * rest of the page alive, which is most of what keeps it from being the dead
 * end convention 4 exists to prevent.
 *
 * TOKENS ONLY, and both themes verified. --parch-50, --parch-border, --ink-700,
 * --ink-400, --primary-700, --serif and --sans are each declared twice in
 * static/workspace/workspace.css, once at :root and once under
 * :root[data-theme="dark"], so every colour here re-points with the theme and
 * no literal can go stale in one of them. That is the exact failure convention
 * 8 names: a hex that looks right in light and vanishes in dark.
 */

/* The covered element is the containing block for its own veil. Declared here
   rather than set by the driver at the moment the veil appears, because
   changing position at that moment would re-parent any absolutely positioned
   descendant mid-interaction and move it under the user. Making a static
   element relative changes nothing about its own layout.

   Both attributes, because there are two shapes. data-slow-cover with no value
   sits on a form that covers itself; data-slow-region marks a container that
   some other control names by selector. The driver refuses to cover a named
   element that lacks data-slow-region, precisely so this rule and that decision
   cannot disagree. */
[data-slow-cover],
[data-slow-region] {
  position: relative;
}

.slow-veil {
  position: absolute;
  inset: 0;
  /* Above .ws-picker__menu's 100, so a dropdown left open when the request went
     out is covered too. Below the dialog's 9999, which is the right way round:
     a veil inside a dialog sits in that dialog's own stacking context anyway,
     and a dialog opening over a veil should win. */
  z-index: 120;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-md, 14px);
  /* The same 88 percent parch mix .loading-overlay uses, for the same reason:
     color-mix keeps the scrim token-driven, so it flips with --parch-50 under
     [data-theme="dark"] rather than needing a second rule. */
  background: color-mix(in srgb, var(--parch-50, #FAF8F3) 88%, transparent);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  animation: slow-veil-in 140ms ease both;
  /* Follow the covered element's corners rather than squaring them off, and
     never let the card escape the region it is describing. The clip is what
     makes the compact rule below a genuine fallback instead of a suggestion. */
  border-radius: inherit;
  overflow: hidden;
  container-type: size;
  container-name: slow-veil;
}

.slow-veil__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
  max-width: 340px;
}

/* A COMPACT FORM FOR A SHORT REGION, and it is not a nicety.
 *
 * The regions this covers are not all cards. A Brain source row is a single
 * line, and the stacked card is about eighty pixels tall, so centring it there
 * puts most of it outside the row it is describing. The first version used a
 * sticky card to solve the opposite problem, a region taller than the viewport,
 * and made this one much worse: on a one-line row the offset pushed the card
 * clear of the row entirely and it floated over the list above. That was found
 * by rendering the page, not by any test.
 *
 * So the card sheds what it cannot fit, in order of what carries the message.
 * The spinner and the label say the click registered and what is happening, and
 * they stay. The note goes, which costs nothing on a short region: it names
 * Escape, and Escape matters when a veil is over most of what you were looking
 * at rather than over one row of a list you can still read.
 *
 * A query on the container's own height rather than the viewport's, because the
 * thing that decides this is how tall the covered element is, and that is a
 * property of the surface rather than of the window. */
@container slow-veil (max-height: 110px) {
  .slow-veil { padding: 0 var(--space-sm, 8px); }
  .slow-veil__card {
    flex-direction: row;
    gap: 8px;
    text-align: left;
    max-width: none;
  }
  .slow-veil__spinner { width: 16px; height: 16px; }
  .slow-veil__note { display: none; }
}

/* Copied number for number from .loading-spinner in _shared/agent-base.css so
   the two spinners are one object. Do not improve either alone. */
.slow-veil__spinner {
  width: 28px;
  height: 28px;
  border: 2px solid var(--parch-border);
  border-top-color: var(--primary-700);
  border-radius: 50%;
  animation: slow-veil-spin 700ms linear infinite;
}

.slow-veil__label {
  margin: 0;
  font-family: var(--serif);
  font-size: var(--text-base, 15px);
  font-weight: 600;
  color: var(--ink-700);
}

.slow-veil__note {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--text-xs, 12px);
  line-height: 1.5;
  color: var(--ink-500);
  transition: opacity var(--motion-slow, 0.3s) ease;
}

@keyframes slow-veil-spin {
  to { transform: rotate(360deg); }
}

@keyframes slow-veil-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* The veil still appears under reduced motion, because it is information and
   not decoration. What goes is the movement: the spinner stops turning, the
   fade-in becomes a plain appearance, and the note swaps without a cross-fade.
   The driver reads the same preference and skips its own copy transition, so
   the two halves agree. */
@media (prefers-reduced-motion: reduce) {
  .slow-veil { animation: none; }
  .slow-veil__spinner { animation: none; }
  .slow-veil__note { transition: none; }
}
