/* Motion system (SPEC §2). Components reference these tokens and keyframes only.
   Panels slide in from the right in 220ms, tabs switch instantly, popovers fade and scale from 98% in
   140ms. Nothing bounces. Reduced motion removes movement and keeps short fades. */
:root {
  --ease-out: cubic-bezier(.22, 1, .36, 1);
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
  --dur-1: 120ms;
  --dur-2: 180ms;
  --dur-3: 240ms;
  --dur-4: 320ms;
  /* Named durations (SPEC §2): tooltips, popovers and menus, the right panel and drawers. */
  --dur-tooltip: 90ms;
  --dur-pop: 140ms;
  --dur-panel: 220ms;
  /* Distances used inside keyframes; reduced motion zeroes them so only opacity remains. */
  --motion-rise: 4px;
  --motion-scale-pop: .98;
  --motion-scale-dialog: .98;
  --motion-press: .98;
  --motion-toast: 12px;
  --motion-panel: 24px;
  --motion-sheet: 24px;
}

@keyframes bramble-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes bramble-fade-out { from { opacity: 1; } to { opacity: 0; } }

/* Popovers and menus: fade and scale from the anchor (useFloating sets transform-origin). */
@keyframes bramble-pop-in {
  from { opacity: 0; transform: translateY(var(--pop-dir, 0px)) scale(var(--motion-scale-pop)); }
  to { opacity: 1; transform: none; }
}
@keyframes bramble-pop-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(var(--pop-dir, 0px)) scale(var(--motion-scale-pop)); }
}
@keyframes bramble-dialog-in {
  from { opacity: 0; transform: scale(var(--motion-scale-dialog)); }
  to { opacity: 1; transform: none; }
}
@keyframes bramble-dialog-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: scale(var(--motion-scale-dialog)); }
}
/* Sheets and drawers; a sheet on the left sets --sheet-dir: -1. */
@keyframes bramble-sheet-in {
  from { opacity: 0; transform: translateX(calc(var(--motion-sheet) * var(--sheet-dir, 1))); }
  to { opacity: 1; transform: none; }
}
@keyframes bramble-sheet-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateX(calc(var(--motion-sheet) * var(--sheet-dir, 1))); }
}
/* The right panel (SPEC §3): in from the right, --dur-panel, --ease-out. */
@keyframes bramble-panel-in {
  from { opacity: 0; transform: translateX(var(--motion-panel)); }
  to { opacity: 1; transform: none; }
}
@keyframes bramble-panel-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateX(var(--motion-panel)); }
}
@keyframes bramble-toast-in {
  from { opacity: 0; transform: translateY(var(--motion-toast)) scale(.98); }
  to { opacity: 1; transform: none; }
}
@keyframes bramble-toast-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateX(var(--motion-toast)); }
}
@keyframes bramble-rise {
  from { opacity: 0; transform: translateY(var(--motion-rise)); }
  to { opacity: 1; transform: none; }
}
@keyframes bramble-progress { from { transform: scaleX(1); } to { transform: scaleX(0); } }
@keyframes bramble-spin { to { transform: rotate(360deg); } }
@keyframes bramble-pulse {
  0% { box-shadow: 0 0 0 0 var(--pulse-color, var(--accent-tint-2)); }
  70% { box-shadow: 0 0 0 5px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
/* bramble-pulse by transform and opacity, so the compositor runs it and the window doesn't repaint
   every frame: a solid dot's ::after, a disc of --pulse-color under the dot (the dot is positioned and
   its parent isolates, so the disc stays above the parent's background), swells and fades. Its
   --pulse-scale is (size + 10px) / size, the 5px ring bramble-pulse draws round the dot. */
@keyframes bramble-pulse-ring {
  0% { transform: none; opacity: 1; }
  70% { transform: scale(var(--pulse-scale, 1.6)); opacity: 0; }
  100% { transform: none; opacity: 0; }
}
@keyframes bramble-breathe { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@keyframes bramble-caret { 0%, 45% { opacity: 1; } 55%, 100% { opacity: 0; } }
@keyframes bramble-skeleton { from { background-position: 150% 0; } to { background-position: -50% 0; } }
@keyframes bramble-draw { to { stroke-dashoffset: 0; } }
@keyframes bramble-berry { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: none; } }

/* Shared utility classes. */
.motion-pop { animation: bramble-pop-in var(--dur-pop) var(--ease-out) both; }
.motion-rise { animation: bramble-rise var(--dur-3) var(--ease-out) both; }
.motion-fade { animation: bramble-fade-in var(--dur-2) var(--ease-out) both; }
.motion-panel { animation: bramble-panel-in var(--dur-panel) var(--ease-out) both; }

/* "Working" status label: a soft highlight sweeps through otherwise neutral text.
   It conveys live state, so it only runs while an agent is working. The highlight is a copy of the
   text (<ShimmerSweep text>, its data-text) in a masked band three times the label's width: the band
   slides right while the copy slides left by as much, so the copy holds still under the moving band.
   Both by transform, so the compositor runs it (a background-position sweep repainted every frame). */
.shimmer-text { position: relative; color: var(--text-2); -webkit-text-fill-color: var(--text-3); }
.shimmer-sweep {
  position: absolute; top: 0; left: 0; width: 300%; height: 100%;
  pointer-events: none; user-select: none; text-overflow: inherit;
  -webkit-mask-image: linear-gradient(90deg, transparent 34%, #000 50%, transparent 66%);
  mask-image: linear-gradient(90deg, transparent 34%, #000 50%, transparent 66%);
  animation: bramble-sweep 2.2s linear infinite;
}
.shimmer-sweep::after {
  content: attr(data-text); position: absolute; top: 0; left: 0; width: calc(100% / 3); height: 100%;
  overflow: hidden; text-overflow: inherit; -webkit-text-fill-color: var(--text);
  animation: bramble-sweep-hold 2.2s linear infinite;
}
@keyframes bramble-sweep { from { transform: translateX(-66.6667%); } to { transform: none; } }
@keyframes bramble-sweep-hold { from { transform: translateX(200%); } to { transform: none; } }

/* The window is hidden or another window has the focus (src/design/idle-window.js): the endless
   animations hold still, so a turn running in the background doesn't redraw the window every frame.
   An endless animation joins this list. (The sessions drawer's .sd-dot keeps its own.) */
:root.is-window-idle :is(
  .shimmer-sweep, .bramble-working, .bw-tail, .bl-w, .bl-b,
  .skeleton, .status-running, .progress.is-indeterminate .progress-fill, .status-pill-waiting .status-pill-dot,
  .chrome-title-dot.is-running, .act-dot.is-running .act-dot-mark, .act-inbox-dot.is-running, .tree-job-ring.is-busy,
  .tv-chip-line.is-indeterminate > span, .tp-dot.is-busy, .render-preview-frame.is-loading, .ds-agent-dot, .bv-live-dot.is-run,
  .rv-meter.is-busy i, .social-status.is-spinning svg, .apps-refreshing svg, .render-mark.is-busy
),
:root.is-window-idle .shimmer-sweep::after, :root.is-window-idle .act-pulse::after, :root.is-window-idle .agent-dot.is-running > span::after,
:root.is-window-idle .plan-step.is-active .plan-check::after, :root.is-window-idle .markdown.is-streaming *::after { animation-play-state: paused; }
/* On screen without the focus (someone waiting beside another app), a running reply's own marks keep moving: the
   working mark and the pulse of its activity line and its tail, two small composited animations. Hidden
   (:root.is-window-hidden), they hold still with the rest. */
:root.is-window-idle:not(.is-window-hidden) .act-line .kind-chip.is-running :is(.bramble-working, .bw-tail),
:root.is-window-idle:not(.is-window-hidden) .act-line .act-pulse::after { animation-play-state: running; }

/* Reduced motion: transforms and shimmers off, fades at most 120ms. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-2: 120ms; --dur-3: 120ms; --dur-4: 120ms; --dur-panel: 120ms;
    --motion-rise: 0px; --motion-scale-pop: 1; --motion-scale-dialog: 1; --motion-press: 1; --motion-toast: 0px; --motion-sheet: 0px; --motion-panel: 0px;
  }
  .shimmer-text { -webkit-text-fill-color: currentColor; }
  .shimmer-sweep, .shimmer-sweep::after { display: none; animation: none; }
  *, *::before, *::after { scroll-behavior: auto !important; }
}
:root[data-reduce-motion="true"] {
  --dur-2: 120ms; --dur-3: 120ms; --dur-4: 120ms; --dur-panel: 120ms;
  --motion-rise: 0px; --motion-scale-pop: 1; --motion-scale-dialog: 1; --motion-press: 1; --motion-toast: 0px; --motion-sheet: 0px; --motion-panel: 0px;
}
:root[data-reduce-motion="true"] .shimmer-text { -webkit-text-fill-color: currentColor; }
:root[data-reduce-motion="true"] .shimmer-sweep, :root[data-reduce-motion="true"] .shimmer-sweep::after { display: none; animation: none; }
:root[data-reduce-motion="true"] *, :root[data-reduce-motion="true"] *::before, :root[data-reduce-motion="true"] *::after { scroll-behavior: auto !important; }
