/* Motion-tokens & bewegingstaal (DSC-182 t/m DSC-192) — sectie N.
 *
 * Eén bron voor duur en easing van alle micro-interacties (11.12).
 * Uitsluitend subtiele, functionele beweging — geen decoratieve animaties.
 *
 *   --duration-fast   150ms  hover/focus-overgangen, toast-exit
 *   --duration-base   220ms  verschijnen: dropdowns, toasts, element-entree, collapse
 *   --duration-panel  300ms  panelen, carrousel en grotere verplaatsingen
 *
 * Easing: --ease-out-soft (tokens-laag, application.tailwind.css) voor alles
 * wat binnenkomt; --ease-in-soft voor wat vertrekt; --ease-spring alleen voor
 * speelse micro-feedback (reactie-pop), nooit voor layout-verplaatsing.
 *
 * Reduced motion (DSC-183): de tokens-laag zet onder prefers-reduced-motion
 * alle animatie- en transitieduren al op 0.01ms. Hier vallen daarbovenop de
 * duurtokens zelf terug (ook transition-delays die op een token staan, zoals
 * de visibility-omslag van panelen) en staan continue animaties expliciet
 * stil. [data-motion="reduced"] spiegelt dat gedrag zodat /design het kan
 * simuleren zonder de OS-instelling om te zetten. */

:root {
  --duration-fast: 150ms;
  --duration-base: 220ms;
  --duration-panel: 300ms;
  /* NAV-1 (mobile UX-audit): vol-scherm doorschuiven in het mobiele
     navigatiepaneel — een maat groter dan --duration-panel, zodat de push als
     een rustige schermwissel leest i.p.v. een snelle paneelbeweging. */
  --duration-stack: 350ms;
  /* Vertrekkende elementen: versnelt het beeld uit. */
  --ease-in-soft: cubic-bezier(0.55, 0, 1, 0.45);
  /* Subtiele veer: lichte overshoot, alleen voor micro-feedback. */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 0.01ms;
    --duration-base: 0.01ms;
    --duration-panel: 0.01ms;
    --duration-stack: 0.01ms;
  }
  .motion-shimmer,
  .motion-spin,
  .motion-drop-placeholder,
  .motion-flash {
    animation: none;
  }
}

[data-motion="reduced"] {
  --duration-fast: 0.01ms;
  --duration-base: 0.01ms;
  --duration-panel: 0.01ms;
  --duration-stack: 0.01ms;
}
[data-motion="reduced"] .motion-shimmer,
[data-motion="reduced"] .motion-spin,
[data-motion="reduced"] .motion-drop-placeholder,
[data-motion="reduced"] .motion-flash {
  animation: none;
}

/* DSC-186 — hover-overgang & kaart-lift: schaduwtoename + 1px lift op
 * klikbare kaarten (directory, org chart, widgets). .is-lifted bestaat
 * voor programmatische demonstratie (replay-knop op /design). */
.motion-lift {
  transition:
    box-shadow var(--duration-fast) ease,
    transform var(--duration-fast) ease;
}
/* PWA-5 (mobile UX-audit): de hover-lift alleen op echte hover-apparaten, anders
 * "plakt" de opgetilde staat na een tik op touch. Focus-visible (toetsenbord) en
 * de programmatische .is-lifted blijven ongeguard. */
.motion-lift:focus-visible,
.motion-lift.is-lifted {
  box-shadow: var(--shadow-card-hover);
  transform: translateY(-1px);
}
@media (hover: hover) {
  .motion-lift:hover {
    box-shadow: var(--shadow-card-hover);
    transform: translateY(-1px);
  }
}

/* DSC-187 — reactie-pop: korte scale-pop (1 → 1.15 → 1) van de gekozen
 * emoji bij het togglen van een reactie; de veer-easing geeft een net
 * voelbare overshoot. Duur op het paneel-token zodat de pop rustig blijft. */
@keyframes ds-pop {
  0% {
    transform: scale(1);
  }
  40% {
    transform: scale(1.15);
  }
  100% {
    transform: scale(1);
  }
}
.motion-pop {
  animation: ds-pop var(--duration-panel) var(--ease-spring);
}

/* DSC-203 — landingsflits: kort oplichtende ring om een element dat zonder
 * scroll-actie van de gebruiker zelf in beeld verschijnt (bv. de eigen
 * comment/reply na het versturen, UX-audit-wave2 juli 2026 auditpunt #5) —
 * zodat duidelijk is WAAR de nieuwe inhoud landde na het scrollIntoView.
 * Langere duur dan de paneel-token (1,4s): een hover-snelle transitie zou
 * hier te vluchtig zijn om als bevestiging te dienen. */
@keyframes ds-flash {
  0% {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-brand) 45%, transparent);
  }
  100% {
    box-shadow: 0 0 0 3px transparent;
  }
}
.motion-flash {
  animation: ds-flash 1.4s var(--ease-out-soft);
}

/* Poef-flits (feedback jul 2026): zacht radiaal lichtje vanuit het midden van
 * een reactie-pill op het moment dat je 'm aanzet — het CSS-deel van de poef
 * (reactions_controller#poef); de emoji-particles komen uit canvas-confetti.
 * Kort en klein: groeit van een puntje naar ~2x pillhoogte en dooft uit. */
@keyframes ds-poef-flits {
  from {
    opacity: 0.85;
    transform: translate(-50%, -50%) scale(0.3);
  }
  to {
    opacity: 0;
    transform: translate(-50%, -50%) scale(1.9);
  }
}
.ds-poef-flits {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 36px;
  height: 36px;
  border-radius: 9999px;
  background: radial-gradient(circle, color-mix(in srgb, var(--color-brand) 55%, white) 0%, transparent 70%);
  pointer-events: none;
  animation: ds-poef-flits 380ms var(--ease-out-soft) forwards;
}

/* DSC-185 — entree-preset voor dropdowns/popovers (vanaf boven het
 * ankerpunt) en toasts (vanaf onder); exit is één korte fade. */
@keyframes ds-enter-up {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}
@keyframes ds-enter-down {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
}
@keyframes ds-exit {
  to {
    opacity: 0;
  }
}
.motion-enter {
  animation: ds-enter-up var(--duration-base) var(--ease-out-soft) backwards;
}
.motion-enter-down {
  animation: ds-enter-down var(--duration-base) var(--ease-out-soft) backwards;
}
.motion-exit {
  animation: ds-exit var(--duration-fast) var(--ease-in-soft) forwards;
}

/* DSC-184 — paneel-slide: zijpanelen (Channels/Pages, quick links) en het
 * notificatie-paneel schuiven over de pagina; visibility volgt ná de
 * slide-out zodat een dicht paneel onbereikbaar is voor focus en
 * screenreaders. De scrim-fade loopt gelijk op (mobiele full-width
 * overlay; desktop-slide-overs dimmen niet, spec 1.1). */
.motion-panel {
  transition: transform var(--duration-panel) var(--ease-out-soft);
}
.motion-panel[data-open="false"] {
  visibility: hidden;
  transition:
    transform var(--duration-panel) var(--ease-in-soft),
    visibility 0s var(--duration-panel);
}
.motion-panel--links[data-open="false"] {
  transform: translateX(-100%);
}
.motion-panel--rechts[data-open="false"] {
  transform: translateX(100%);
}
.motion-scrim {
  transition: opacity var(--duration-panel) ease;
}
.motion-scrim[data-open="false"] {
  opacity: 0;
  pointer-events: none;
}

/* DSC-188 — slide-track: carrouselwissel (transform komt uit de
 * carousel-controller; swipe blijft onder reduced motion werken). */
.motion-slide {
  transition: transform var(--duration-panel) var(--ease-out-soft);
}

/* DSC-182: demoloper voor de duur- en easing-tegels (/design, sectie N).
 * De loper is precies zo breed als de af te leggen baan (baanbreedte min
 * 2x 4px inset en het 16px-balletje) en schuift over zijn eigen breedte.
 * Zo eindigt het balletje op elke tegelbreedte netjes binnen het kader,
 * ook in de eindstand; duur en easing zet de tegel er zelf als
 * utility-klassen bij. */
.motion-runner {
  width: calc(100% - 1.5rem);
}
.motion-runner[data-open="true"] {
  transform: translateX(100%);
}
/* De easing-tegel toont ook --ease-spring, die tot ~8% voorbij de eindstand
 * doorschiet. De drie easing-lopers leggen daarom dezelfde, iets kortere baan
 * af (blijven zo onderling uitgelijnd) zodat de spring-overshoot ook op de
 * piek binnen het kader valt. */
.motion-runner--easing[data-open="true"] {
  transform: translateX(calc(100% - 1.25rem));
}

/* DSC-189 — uitklap-/inklapovergang: composer, accordions en
 * org-chart-takken. Grid-template-rows animeert naar de natuurlijke
 * hoogte; visibility maakt ingeklapte inhoud ontoegankelijk voor focus
 * en screenreaders (pas ná de inklap, direct bij uitklap). */
.motion-collapse {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
  transition:
    grid-template-rows var(--duration-base) var(--ease-out-soft),
    visibility 0s var(--duration-base);
}
.motion-collapse[data-expanded="true"] {
  grid-template-rows: 1fr;
  visibility: visible;
  transition: grid-template-rows var(--duration-base) var(--ease-out-soft);
}
/* overflow: clip met 6px clip-margin (app-breed focus-patroon): de regio
 * clippt tijdens de overgang, maar laat de 2px focus-ring met 2px offset
 * van velden aan de rand (composer-titel, announcement-datumveld) volledig
 * zichtbaar. Browsers zonder overflow-clip-margin clippen op de rand zelf. */
.motion-collapse > * {
  min-height: 0;
  overflow: clip;
  overflow-clip-margin: 6px;
}
/* Na afloop van de uitklap-overgang zet .is-settled (tree-controller) de
 * clipping weer los, zodat zwevende elementen in een uitgeklapte tak
 * (contextmenu's in de beheer-boom) niet worden afgeknipt. */
.motion-collapse.is-settled[data-expanded="true"] > * {
  overflow: visible;
}

/* DSC-191 — skeleton-shimmer (gedeeld met de skeletons in sectie M):
 * rustige lichtstreep over een line-kleurig vlak, 1.8s per doorloop. */
@keyframes ds-shimmer {
  from {
    background-position: 200% 0;
  }
  to {
    background-position: -200% 0;
  }
}
.motion-shimmer {
  background-color: var(--color-line);
  background-image: linear-gradient(
    100deg,
    transparent 38%,
    color-mix(in srgb, white 60%, transparent) 50%,
    transparent 62%
  );
  background-size: 200% 100%;
  animation: ds-shimmer 1.8s linear infinite;
}

/* DSC-192 — laad-spinner-rotatie: in-veld-indicator bij live search;
 * herbruikbaar voor elke kleine laad-indicator. Onder reduced motion
 * bevriest de ring tot een statische indicator. */
@keyframes ds-spin {
  to {
    transform: rotate(360deg);
  }
}
.motion-spin {
  animation: ds-spin 0.9s linear infinite;
}

/* DSC-190 — drag-&-drop-feedback (SortableJS): ghost op de oude positie,
 * pulserende placeholder op de doelpositie en een dunne drop-indicator
 * voor lijst-herordening. */
.motion-drag-ghost {
  opacity: 0.4;
}
@keyframes ds-placeholder-pulse {
  50% {
    background-color: color-mix(in srgb, var(--color-brand) 14%, transparent);
  }
}
.motion-drop-placeholder {
  border: 2px dashed var(--color-brand);
  border-radius: var(--radius-lg);
  background-color: color-mix(in srgb, var(--color-brand) 6%, transparent);
  animation: ds-placeholder-pulse 1.2s ease-in-out infinite;
}
.motion-drop-indicator {
  position: relative;
  height: 2px;
  border-radius: 9999px;
  background-color: var(--color-brand);
}
.motion-drop-indicator::before {
  content: "";
  position: absolute;
  top: -3px;
  left: -3px;
  height: 8px;
  width: 8px;
  border-radius: 9999px;
  background-color: var(--color-brand);
}

/* NAV-1 (mobile UX-audit) — doorschuif-overgang van het mobiele
 * navigatiepaneel (menu_stack_controller + layouts/_mobile_menu_panel):
 * iOS-achtige push. De subweergave schuift van rechts over de rootlijst heen;
 * de rootlijst reist als parallax een kwart mee naar links en dimt licht, zodat
 * de beweging diepte heeft i.p.v. een plat paneel dat "verschijnt". Zelfde
 * transitie omgekeerd bij pop (terugknop). Puur transform/opacity (composited,
 * geen layout-werk) en de duur/easing komen uit de motion-tokens, dus
 * reduced-motion maakt dit vanzelf instant. Het component bestaat alleen in het
 * mobiele paneel (md:hidden), dus desktop raakt dit nooit. */
.ds-menu-stack-root {
  transition:
    transform var(--duration-stack) var(--ease-out-soft),
    opacity var(--duration-stack) var(--ease-out-soft);
}
.ds-menu-stack-root[data-pushed="true"] {
  transform: translateX(-25%);
  opacity: 0.4;
}
.ds-menu-stack-view {
  transform: translateX(100%);
  transition: transform var(--duration-stack) var(--ease-out-soft);
  will-change: transform;
  /* Zachte linkerrand-schaduw: de inschuivende laag leest als bovenliggend. */
  box-shadow: -16px 0 32px rgb(22 22 22 / 0.1);
}
.ds-menu-stack-view[data-open="true"] {
  transform: translateX(0);
}
