/* motion.css — every new motion recipe from the 2026-09-17 animation-
   opportunities audit (.superpowers/pre-testing-2026-09-17/animation-
   opportunities.md). Linked LAST in base.html, after every other
   stylesheet, so it can extend selectors owned by app.css/tareas.css/
   asistente.css/crm.css/guia.css without editing those files. Tokens only
   (tokens.css); transform + opacity only; exponential ease-out only
   (never elastic, never bare ease-in); nothing over 300ms except the one
   precedented ambient loop (item 1, matching asistente.css's existing
   ai-breathe sparkle) and the completion springs (item 14: the ONE place a
   small overshoot is allowed, DESIGN.md section 9, Joe 2026-09-23).
   Grouped by the audit's item numbers. */

/* ---- Item 1: assistant composer pending state ("Pensando…") ----
   Visible only while #ai-composer/#agent-composer's htmx request is in
   flight (htmx toggles .htmx-request on the hx-indicator target). Dots use
   currentColor, not coral: coral is never a status. */
.ai-pending {
  display: none;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.ai-pending.htmx-request { display: inline-flex; }
.ai-pending-dots { display: inline-flex; gap: 3px; }
.ai-pending-dots i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  opacity: .6;
}
@media (prefers-reduced-motion: no-preference) {
  .ai-pending.htmx-request .ai-pending-dots i {
    opacity: .3;
    animation: ai-pending-dot 1200ms var(--ease-in-out) infinite;
  }
  .ai-pending.htmx-request .ai-pending-dots i:nth-child(2) { animation-delay: 160ms; }
  .ai-pending.htmx-request .ai-pending-dots i:nth-child(3) { animation-delay: 320ms; }
  @keyframes ai-pending-dot {
    0%, 60%, 100% { opacity: .3; }
    30% { opacity: 1; }
  }
}

/* ---- Item 3: document quick view <dialog> enter/exit ----
   Enter: opacity + scale(--enter-scale), 240ms quint, centred (modals are
   not trigger-anchored). Scrim: opacity, 200ms quart. Exit: 140ms quart,
   faster than the entrance. The @supports block holds the dialog in the
   top layer while it fades out (Chromium only; other engines keep today's
   instant open/close). */
@media (prefers-reduced-motion: no-preference) {
  .quickview-dialog[open] {
    transition: opacity var(--duration-modal) var(--ease-out-quint),
                transform var(--duration-modal) var(--ease-out-quint);
  }
  .quickview-dialog[open]::backdrop {
    transition: opacity var(--duration-base) var(--ease-out-quart);
  }
  @starting-style {
    .quickview-dialog[open] { opacity: 0; transform: scale(var(--enter-scale)); }
    .quickview-dialog[open]::backdrop { opacity: 0; }
  }
  @supports (overlay: auto) {
    .quickview-dialog {
      opacity: 0;
      transform: scale(var(--enter-scale));
      transition: opacity var(--duration-fast) var(--ease-out-quart),
                  transform var(--duration-fast) var(--ease-out-quart),
                  overlay var(--duration-fast) allow-discrete,
                  display var(--duration-fast) allow-discrete;
    }
    .quickview-dialog[open] { opacity: 1; transform: none; }
    .quickview-dialog::backdrop {
      opacity: 0;
      transition: opacity var(--duration-fast) var(--ease-out-quart),
                  overlay var(--duration-fast) allow-discrete,
                  display var(--duration-fast) allow-discrete;
    }
    .quickview-dialog[open]::backdrop { opacity: 1; }
  }
}

/* ---- Item 5: press feedback for the secondary button tier ----
   .btn-accent/.btn-primary/.btn-danger already have a press state
   (app.css); this tier (plus .ai-chip) had none. Also gives these controls
   their hover colour easing, so they drop out of item 10's sweep. */
.btn-secondary, .row-done, .side-close, .prio-op, .row-toggle, .ai-chip {
  transition: background-color var(--duration-fast) var(--ease-out-quart),
              border-color var(--duration-fast) var(--ease-out-quart),
              color var(--duration-fast) var(--ease-out-quart),
              transform var(--duration-fast) var(--ease-out-quart);
}
.btn-secondary:active, .row-done:active, .side-close:active,
.prio-op:active, .row-toggle:active, .ai-chip:active {
  transform: scale(var(--press-scale));
}

/* ---- Item 7: on-screen guide spotlight gains an opacity fade ----
   Overrides guia.css's unconditional 4-property transition (top/left/
   width/height) with the same list plus opacity, gated to no-preference —
   guia.css is owned elsewhere so the override lives here, where it loads
   after guia.css and wins the cascade on equal specificity. */
@media (prefers-reduced-motion: no-preference) {
  .guia-spot {
    transition: top var(--duration-base) var(--ease-out-quart),
      left var(--duration-base) var(--ease-out-quart),
      width var(--duration-base) var(--ease-out-quart),
      height var(--duration-base) var(--ease-out-quart),
      opacity var(--duration-base) var(--ease-out-quart);
  }
  @starting-style { .guia-spot { opacity: 0; } }
}

/* ---- Item 8: popovers open from their trigger ----
   Avatar menu + staff contact card: opacity + scale(--enter-scale) from the
   trigger corner, 140ms quart. Never from scale(0). No translate: both
   popovers sit over content where a shift could create overflow. */
@media (prefers-reduced-motion: no-preference) {
  .avatar-menu[open] > .avatar-menu-panel {
    transform-origin: top right;
    animation: motion-pop-in var(--duration-fast) var(--ease-out-quart);
  }
  .contact-pop[open] > .contact-pop-card {
    transform-origin: top left;
    animation: motion-pop-in var(--duration-fast) var(--ease-out-quart);
  }
  @keyframes motion-pop-in {
    from { opacity: 0; transform: scale(var(--enter-scale)); }
  }
}

/* ---- Item 9: disclosure content fades in ----
   Feed entry detail, Inicio mail preview: opacity only, 140ms quart, no
   movement, no height animation (near-imperceptible tier — tens/day). Not
   applied to details.hp or .feed-daywrap: both render open on load, which
   would replay the fade on every page load. */
@media (prefers-reduced-motion: no-preference) {
  .feed-entry[open] > .feed-detail,
  .mail-preview > td {
    animation: motion-disclose-in var(--duration-fast) var(--ease-out-quart);
  }
  @keyframes motion-disclose-in {
    from { opacity: 0; }
  }
}

/* ---- Item 10: hover colour easing on the controls that still snap ----
   app.css's controls already ease colour over 140ms; these (crm.css,
   tareas.css, asistente.css, app.css) changed in one frame. Colour/
   background/border only — no transform anywhere, binding for
   .record-tab (an overflow-x scroll strip: a transform there recreates the
   phantom scrollbar, guarded by test_record_tabs_pins_overflow_y_and_uses_no_transform).
   .ai-chip and the item 5 controls already got this above. */
.record-tab,
.subnav-item, .seg-item, .wk-nav, .wk-day,
.ai-open, .ai-rail,
.category-chip, .quickview-close, .avatar-menu-trigger {
  transition: color var(--duration-fast) var(--ease-out-quart),
              background-color var(--duration-fast) var(--ease-out-quart),
              border-color var(--duration-fast) var(--ease-out-quart);
}

/* ---- Item 11: toasts (UI improvements phase A, 2026-09-23) ----
   Enter: rise 12px from --enter-scale, quint, 240ms. Exit: fall 8px and
   fade, 140ms. toast.js removes the node on a timer either way, so under
   reduced motion the toast simply appears and disappears. */
.toast-undo, .toast-close {
  transition: color var(--duration-fast) var(--ease-out-quart),
              background-color var(--duration-fast) var(--ease-out-quart);
}
@media (prefers-reduced-motion: no-preference) {
  .toast {
    animation: motion-toast-in var(--duration-modal) var(--ease-out-quint);
  }
  .toast.is-out {
    animation: motion-toast-out var(--duration-fast) var(--ease-out-quart) forwards;
  }
  @keyframes motion-toast-in {
    from { opacity: 0; transform: translateY(12px) scale(var(--enter-scale)); }
  }
  @keyframes motion-toast-out {
    to { opacity: 0; transform: translateY(8px); }
  }
}

/* ---- Item 12: side sheet (UI improvements phase C, 2026-09-23) ----
   Slides 32px in from the right, quint, 240ms; leaves faster (140ms) than it
   arrives. sheet.js closes on a timer either way. */
.sheet-close {
  transition: color var(--duration-fast) var(--ease-out-quart),
              background-color var(--duration-fast) var(--ease-out-quart);
}
@media (prefers-reduced-motion: no-preference) {
  .sheet-dialog[open] {
    animation: motion-sheet-in var(--duration-modal) var(--ease-out-quint);
  }
  .sheet-dialog[open]::backdrop {
    animation: motion-sheet-fade var(--duration-modal) var(--ease-out-quint);
  }
  .sheet-dialog.is-closing {
    animation: motion-sheet-out var(--duration-fast) var(--ease-out-quart) forwards;
  }
  @keyframes motion-sheet-in {
    from { opacity: 0; transform: translateX(32px); }
  }
  @keyframes motion-sheet-out {
    to { opacity: 0; transform: translateX(24px); }
  }
  @keyframes motion-sheet-fade {
    from { opacity: 0; }
  }
}

/* ---- Item 13: subtask rows open and close (UI improvements D5,
   2026-09-23). grid-template-rows is the one non-transform property the
   brand allows, for exactly this: "how tall is this list". 280ms quint,
   the chevron turns with it. tasks_list.js hides the row once closed. ---- */
.sub-toggle {
  transition: color var(--duration-fast) var(--ease-out-quart),
              background-color var(--duration-fast) var(--ease-out-quart);
}
@media (prefers-reduced-motion: no-preference) {
  .sub-acc { transition: grid-template-rows var(--duration-modal) var(--ease-out-quint); }
  .sub-toggle svg { transition: transform var(--duration-base) var(--ease-out-quint); }
}

/* ---- Item 14: completion tick (UI improvements F, 2026-09-23) ----
   The one overshoot in the app (DESIGN.md section 9): the tick fills leaf
   and springs past its size once, 420ms, peak 1.10. The row tints leaf,
   strikes through and fades before tasks_list.js submits. Reduced motion:
   tasks_list.js skips the wait and the page confirms with the toast. */
.row-done.is-ticking {
  background: var(--leaf-600);
  border-color: var(--leaf-600);
  color: var(--paper);
}
.tbl tr.is-completing td { background: var(--leaf-50); }
.tbl tr.is-completing .t-title,
.sub-item.is-completing .sub-title {
  color: var(--color-text-muted);
  text-decoration: line-through;
}
.tbl tbody td {
  transition: background-color var(--duration-base) var(--ease-out-quart);
}
.tbl tr.is-leaving td > *,
.sub-item.is-leaving > * { opacity: .45; }
@media (prefers-reduced-motion: no-preference) {
  .row-done.is-ticking {
    animation: motion-complete-tick 420ms linear;
  }
  .tbl tr.is-leaving td > *,
  .sub-item.is-leaving > * {
    transition: opacity var(--duration-fast) var(--ease-out-quart);
  }
  @keyframes motion-complete-tick {
    0% { transform: scale(0.86); }
    35% { transform: scale(1.1); }
    60% { transform: scale(0.97); }
    80% { transform: scale(1.02); }
    100% { transform: scale(1); }
  }
}

/* ---- Item 15: a project closes (UI improvements F, 2026-09-23) ----
   The second completion spring (DESIGN.md section 9): the check springs in
   once, right after closing, 600ms, peak 1.12; the facts strip rises in
   after it. Reloads show it still (no .is-closing). The confirm dialog
   enters from --enter-scale like every dialog. */
@media (prefers-reduced-motion: no-preference) {
  .close-mark.is-closing {
    animation: motion-complete-close 600ms linear;
  }
  .close-mark.is-closing + .close-facts {
    animation: motion-close-facts var(--duration-modal) var(--ease-out-quint) both;
    animation-delay: 240ms;
  }
  .confirm-dialog[open] {
    animation: motion-confirm-in var(--duration-modal) var(--ease-out-quint);
  }
  @keyframes motion-complete-close {
    0% { transform: scale(0.6); opacity: 0; }
    30% { transform: scale(1.12); opacity: 1; }
    55% { transform: scale(0.96); }
    75% { transform: scale(1.02); }
    100% { transform: scale(1); }
  }
  @keyframes motion-close-facts {
    from { opacity: 0; transform: translateY(6px); }
  }
  @keyframes motion-confirm-in {
    from { opacity: 0; transform: scale(var(--enter-scale)); }
  }
}

/* ---- Item 16: the portal switch's knob slides (2026-09-23): 140ms quart. */
@media (prefers-reduced-motion: no-preference) {
  .switch, .switch::after {
    transition: background-color var(--duration-fast) var(--ease-out-quart),
                transform var(--duration-fast) var(--ease-out-quart);
  }
}
