/* ─────────────────────────────────────────────────────────────────────────
   MOTION, FOCUS AND PENDING STATE

   Where "consumer-grade smooth" is actually delivered. Inconsistent
   transition timing is the single biggest tell of a hand-built UI, and the
   fix is not more animation — it is the same two easings and three durations
   everywhere. specs/design-system.md §5 phase 5.
   ───────────────────────────────────────────────────────────────────────── */

@layer components {
  /* ── Focus ─────────────────────────────────────────────────────────
     An accessibility win and a polish win at once. :focus-visible only
     shows for keyboard users, so pointer users never see a ring they did
     not ask for. --focus-ring is accent-derived, so it re-colours per app.
     :where() keeps specificity at zero, so any component can override it
     without an escalation fight. */
  :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: var(--focus-ring-width) solid var(--focus-ring);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
  }

  /* A focus ring should never be clipped away by an overflow container. */
  :where(a, button):focus-visible { position: relative; z-index: 1; }

  /* ── HTMX pending state ────────────────────────────────────────────
     HTMX adds .htmx-request to the element issuing a request (or its
     hx-indicator target) for the life of that request. Fading the element
     it is about to replace is what makes a swap read as "loading" rather
     than "frozen".

     `body` is excluded, and that exclusion is load-bearing rather than
     cosmetic. A bare `htmx.ajax(...)` call with no `source` uses
     document.body as the issuing element, so the whole page becomes the
     indicator — and htmx 1.9.10 tracks the class with a per-element
     requestCount that can drop below zero (each of onload/onerror/onabort
     decrements, so one request seen twice leaves it at -1). Once negative
     it never returns to 0, the class is never removed, and the entire page
     is left dimmed with every button and input dead to pointer events. */
  .htmx-request:not(body) {
    opacity: 0.55;
    transition: opacity var(--dur-fast) var(--ease-out);
  }

  .htmx-request:not(body) :where(button, input, select, textarea) {
    pointer-events: none;
  }

  /* Excluding body from the dim must not mean "no feedback at all": a bare
     htmx.ajax() is how the conversation panel, the kanban board and the calendar
     load, and a click that changes nothing on screen gets clicked again, stacking
     requests into the same target. So body gets a cue that cannot strand the
     page if the class sticks — nothing is dimmed, nothing is made inert. */
  body.htmx-request { cursor: progress; }

  body.htmx-request::after {
    content: "";
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
    block-size: 2px;
    background: var(--color-accent);
    animation: htmx-page-progress calc(var(--dur-slow) * 4) var(--ease-in-out) infinite;
    transform-origin: 0 50%;
    pointer-events: none;
    z-index: 100;
  }

  @keyframes htmx-page-progress {
    from { transform: scaleX(0); }
    50%  { transform: scaleX(0.7); }
    to   { transform: scaleX(1); }
  }

  /* Opt-in skeleton for a region that renders empty while it loads. */
  .skeleton {
    background: linear-gradient(
      90deg,
      var(--color-surface-2) 25%,
      var(--color-border-light) 37%,
      var(--color-surface-2) 63%
    );
    background-size: 400% 100%;
    border-radius: var(--radius-sm);
    color: transparent;
    animation: skeleton-sweep 1.2s var(--ease-in-out) infinite;
  }

  @keyframes skeleton-sweep {
    from { background-position: 100% 50%; }
    to   { background-position: 0 50%; }
  }

  /* ── Container queries ─────────────────────────────────────────────
     A card in a narrow column should lay out for its column, not for the
     viewport — a sidebar card at 1600px wide is still a narrow card. */
  .card { container-type: inline-size; }

  @container (max-width: 22rem) {
    .card__header,
    .card__footer {
      flex-wrap: wrap;
      gap: var(--space-1);
    }

    .card__body { padding: var(--space-3); }
  }

  /* ── Reduced motion ────────────────────────────────────────────────
     Honour the OS setting. Transitions collapse to instant rather than
     being removed, so nothing depending on transitionend breaks. */
  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      animation-duration: 1ms;
      animation-iteration-count: 1;
      transition-duration: 1ms;
      scroll-behavior: auto;
    }
  }
}

/* ── View Transitions on HTMX swaps ──────────────────────────────────
   Enabled globally in crm/js/htmx_config.js. Baseline newly available
   (2025-10) and degrades to an instant swap where unsupported, so it costs
   nothing on older browsers. Kept out of a layer: ::view-transition
   pseudo-elements live on the document root, not in the page's cascade. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--dur-fast);
  animation-timing-function: var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none;
  }
}
