/* ── motion ─────────────────────────────────────────────────────────────── */

/* All of it opt-out. Every state above is legible from colour, glyph, and text
   alone, so switching motion off removes emphasis and never information. */
@media (prefers-reduced-motion: no-preference) {
  .pi-live[data-state="live"] .pi-live-dot {
    animation: pi-pulse 2.4s ease-in-out infinite;
  }

  /* Pips are revealed by JS removing .is-pending on a stagger, so the chain
     resolves left to right at reading speed. */
  .pi-pip {
    transition: opacity 220ms ease, transform 220ms ease;
  }

  .pi-pip.is-pending {
    opacity: 0;
    transform: translateY(2px);
  }

  .pi-approval-card {
    animation: pi-card-in 260ms cubic-bezier(0.16, 1, 0.3, 1);
  }

  /* A pending card wears a slow light circling its edge — pending, stated by
     the border itself. The amber gradient repaints over padding-box and the
     conic sweep owns the 1px border-box ring behind it. Browsers without
     @property never interpolate --pi-sweep and keep the static border above. */
  @supports (background: conic-gradient(from 1deg, red, red)) {
    .pi-approval-card {
      border-color: transparent;
      background:
        linear-gradient(
          180deg,
          color-mix(in oklch, var(--sp-color-warning) 9%, var(--sp-color-terminal-header)),
          var(--sp-color-terminal-header)
        ) padding-box,
        conic-gradient(
          from var(--pi-sweep),
          color-mix(in oklch, var(--sp-color-warning) 65%, transparent),
          color-mix(in oklch, var(--sp-color-warning) 14%, transparent) 30%,
          color-mix(in oklch, var(--sp-color-warning) 14%, transparent) 70%,
          color-mix(in oklch, var(--sp-color-warning) 65%, transparent)
        ) border-box;
      animation:
        pi-card-in 260ms cubic-bezier(0.16, 1, 0.3, 1),
        pi-border-sweep 6s linear infinite;
    }
  }

  /* The auto-approved variant is settled, not pending: it arrives, but the
     amber sweep that says "waiting on you" would be a lie on it. */
  .pi-approval-card--auto {
    border-color: color-mix(in oklch, var(--sp-color-success) 25%, transparent);
    background: linear-gradient(
      180deg,
      color-mix(in oklch, var(--sp-color-success) 7%, var(--sp-color-terminal-header)),
      var(--sp-color-terminal-header)
    );
    animation: pi-card-in 260ms cubic-bezier(0.16, 1, 0.3, 1);
  }

  .pi-blocked.is-arriving {
    animation: pi-block-in 300ms cubic-bezier(0.36, 0.07, 0.19, 0.97);
  }

  /* The blocked card's left accent carries a slow travelling light. */
  .pi-blocked::before {
    opacity: 1;
    animation: pi-edge-shimmer 4s ease-in-out infinite;
  }

  .pi-jump {
    animation: pi-card-in 180ms ease-out;
  }

  /* Prose arrives as a finished unit, so it gets an arrival. Same easing as the
     approval card, because both are "a thing resolved and is now here". */
  .pi-reveal {
    animation: pi-card-in 260ms cubic-bezier(0.16, 1, 0.3, 1);
  }

  .pi-working-dot {
    animation: pi-pulse-dot 1.4s ease-in-out infinite;
  }
}

@keyframes pi-pulse-dot {
  0%, 100% { opacity: 0.35; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1); }
}

@keyframes pi-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklch, var(--sp-color-success) 55%, transparent); }
  50% { box-shadow: 0 0 0 4px color-mix(in oklch, var(--sp-color-success) 0%, transparent); }
}

@keyframes pi-card-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

@keyframes pi-border-sweep {
  to { --pi-sweep: 360deg; }
}

@keyframes pi-edge-shimmer {
  from { background-position: 0 300%; }
  to { background-position: 0 -300%; }
}

/* A short, small shake. Enough to say "this stopped", not enough to be a toy. */
@keyframes pi-block-in {
  0% { opacity: 0; transform: translateX(0); }
  30% { opacity: 1; transform: translateX(-3px); }
  55% { transform: translateX(3px); }
  75% { transform: translateX(-2px); }
  100% { transform: none; }
}

/* ── narrow ─────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {
  .pi-terminal .terminal-body {
    min-height: 200px;
    padding: var(--sp-space-3);
    font-size: 0.8rem;
  }

  .pi-terminal .terminal-header {
    flex-wrap: wrap;
    row-gap: var(--sp-space-1);
  }

  /* The identity keeps its lock but yields width to the transcript. */
  .pi-user-chip > span {
    max-width: 8rem;
  }

  /* The indent that shapes the wide transcript is a tax at phone widths — the
     column is barely 40ch, so the answer needs every one of them. Prompts keep
     their hairline rule, which still carries the act grouping. */
  .pi-terminal.is-replay .terminal-body .pi-prose,
  .pi-terminal.is-replay .terminal-body .pi-tool,
  .pi-terminal.is-replay .terminal-body .pi-rail-line,
  .pi-terminal.is-replay .terminal-body .pi-blocked,
  .pi-terminal.is-replay .terminal-body .pi-note {
    margin-left: 0;
  }

  .pi-terminal.is-replay .terminal-body .pi-prose {
    padding-left: var(--sp-space-2);
  }

  .pi-terminal .pi-turn-user {
    margin-top: var(--sp-space-4);
    padding-top: var(--sp-space-2);
  }

  /* Chrome tightens; the transcript is what the height is for. */
  .pi-composer {
    padding: var(--sp-space-3);
  }

  .pi-approvals:not(:empty) {
    padding: var(--sp-space-2) var(--sp-space-3);
  }

  .pi-gate {
    padding: var(--sp-space-3);
    font-size: 0.8rem;
  }

  /* The kv ledger's two columns fight for width a phone does not have. */
  .pi-approval-kv {
    grid-template-columns: 1fr;
    gap: 0 var(--sp-space-3);
  }

  .pi-approval-kv dt {
    line-height: 1.4;
  }

  .pi-approval-kv dd {
    margin-bottom: var(--sp-space-1);
  }

  /* Chips give way before the verdict does. */
  .pi-blocked-meta {
    margin-left: 0;
    width: 100%;
  }

  /* The meters scroll rather than wrapping into a second row that pushes the
     transcript off the first screen. */
  .pi-meters {
    order: 3;
    width: 100%;
    margin-left: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .pi-meters::-webkit-scrollbar { display: none; }

  /* The rail is the one thing that must never be truncated: a chain with a pip
     hidden off-screen is a chain the viewer cannot verify. */
  .pi-rail {
    flex-wrap: wrap;
    row-gap: 0.2rem;
  }

  .pi-approval-actions,
  .pi-gate-actions {
    flex-direction: column;
  }

  /* Args over the cleared chain, single column. */
  .pi-approval-grid {
    grid-template-columns: 1fr;
  }

  .pi-tool-state {
    display: none;
  }
}
