/* ═══════════════════════════════════════════════════════════════
   Senshin Motion System
   Three presets: Full / Subtle / Reduced
   Applied via data-motion attribute on <html>
   Respects prefers-reduced-motion automatically
   ═══════════════════════════════════════════════════════════════ */

:root {
  --motion-duration-fast: 120ms;
  --motion-duration-normal: 200ms;
  --motion-duration-slow: 350ms;
  --motion-duration-page: 400ms;
  --motion-easing: cubic-bezier(0.25, 0.1, 0.25, 1);
  --motion-easing-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --motion-easing-out: cubic-bezier(0, 0, 0.2, 1);
  --motion-easing-in: cubic-bezier(0.4, 0, 1, 1);
  --motion-scale: 1;
}

/* ── Full motion (default) ───────────────────────────────── */
html[data-motion="full"],
html:not([data-motion]) {
  --motion-scale: 1;
}

/* ── Subtle motion ───────────────────────────────────────── */
html[data-motion="subtle"] {
  --motion-scale: 0.5;
  --motion-duration-fast: 80ms;
  --motion-duration-normal: 140ms;
  --motion-duration-slow: 220ms;
  --motion-duration-page: 250ms;
  --motion-easing-spring: var(--motion-easing);
}

/* ── Reduced motion ──────────────────────────────────────── */
html[data-motion="reduced"] {
  --motion-scale: 0;
  --motion-duration-fast: 0ms;
  --motion-duration-normal: 0ms;
  --motion-duration-slow: 0ms;
  --motion-duration-page: 0ms;
}

/* ── OS-level reduced motion override ────────────────────── */
@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-scale: 0;
    --motion-duration-fast: 0ms;
    --motion-duration-normal: 0ms;
    --motion-duration-slow: 0ms;
    --motion-duration-page: 0ms;
  }
}

/* ── Transition utilities ────────────────────────────────── */

.motion-fade {
  transition: opacity var(--motion-duration-normal) var(--motion-easing);
}

.motion-slide {
  transition: transform var(--motion-duration-normal) var(--motion-easing),
              opacity var(--motion-duration-normal) var(--motion-easing);
}

.motion-scale {
  transition: transform var(--motion-duration-fast) var(--motion-easing-spring);
}

.motion-all {
  transition: all var(--motion-duration-normal) var(--motion-easing);
}

/* ── Enter / exit states ─────────────────────────────────── */

.motion-enter {
  opacity: 0;
  transform: translateY(calc(8px * var(--motion-scale)));
}

.motion-enter-active {
  opacity: 1;
  transform: translateY(0);
  transition: opacity var(--motion-duration-normal) var(--motion-easing),
              transform var(--motion-duration-normal) var(--motion-easing-out);
}

.motion-exit {
  opacity: 1;
  transform: translateY(0);
}

.motion-exit-active {
  opacity: 0;
  transform: translateY(calc(-4px * var(--motion-scale)));
  transition: opacity var(--motion-duration-fast) var(--motion-easing),
              transform var(--motion-duration-fast) var(--motion-easing-in);
}

/* ── Page transition ─────────────────────────────────────── */

.page-enter {
  opacity: 0;
  transform: translateX(calc(16px * var(--motion-scale)));
}

.page-enter-active {
  opacity: 1;
  transform: translateX(0);
  transition: opacity var(--motion-duration-page) var(--motion-easing),
              transform var(--motion-duration-page) var(--motion-easing-out);
}

.page-exit-active {
  opacity: 0;
  transform: translateX(calc(-16px * var(--motion-scale)));
  transition: opacity var(--motion-duration-fast) var(--motion-easing),
              transform var(--motion-duration-fast) var(--motion-easing-in);
}

/* ── Interactive feedback ────────────────────────────────── */

.motion-press {
  transition: transform var(--motion-duration-fast) var(--motion-easing);
}

.motion-press:active {
  transform: scale(calc(1 - 0.03 * var(--motion-scale)));
}

.motion-hover {
  transition: transform var(--motion-duration-fast) var(--motion-easing-spring),
              box-shadow var(--motion-duration-fast) var(--motion-easing);
}

@media (hover: hover) {
  .motion-hover:hover {
    transform: translateY(calc(-2px * var(--motion-scale)));
    box-shadow: 0 4px 12px rgba(0, 0, 0, calc(0.08 * var(--motion-scale)));
  }
}

/* ── Skeleton loading pulse ──────────────────────────────── */

@keyframes skeleton-pulse {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 0.8; }
}

.skeleton {
  animation: skeleton-pulse calc(1.5s * max(var(--motion-scale), 0.01)) ease-in-out infinite;
  background: linear-gradient(90deg, #e2e8f0 25%, #f1f5f9 50%, #e2e8f0 75%);
  background-size: 200% 100%;
  border-radius: 4px;
}

html[data-motion="reduced"] .skeleton,
@media (prefers-reduced-motion: reduce) {
  .skeleton {
    animation: none;
    opacity: 0.6;
  }
}

/* ── Spinner ─────────────────────────────────────────────── */

@keyframes spin {
  to { transform: rotate(360deg); }
}

.motion-spinner {
  animation: spin calc(0.8s * max(var(--motion-scale), 0.01)) linear infinite;
}

html[data-motion="reduced"] .motion-spinner {
  animation-duration: 0.8s;
}

/* ── Stagger children ────────────────────────────────────── */

.stagger-children > * {
  opacity: 0;
  transform: translateY(calc(6px * var(--motion-scale)));
  animation: stagger-in var(--motion-duration-normal) var(--motion-easing-out) forwards;
}

.stagger-children > *:nth-child(1) { animation-delay: 0ms; }
.stagger-children > *:nth-child(2) { animation-delay: calc(40ms * var(--motion-scale)); }
.stagger-children > *:nth-child(3) { animation-delay: calc(80ms * var(--motion-scale)); }
.stagger-children > *:nth-child(4) { animation-delay: calc(120ms * var(--motion-scale)); }
.stagger-children > *:nth-child(5) { animation-delay: calc(160ms * var(--motion-scale)); }
.stagger-children > *:nth-child(6) { animation-delay: calc(200ms * var(--motion-scale)); }
.stagger-children > *:nth-child(n+7) { animation-delay: calc(240ms * var(--motion-scale)); }

@keyframes stagger-in {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

html[data-motion="reduced"] .stagger-children > * {
  opacity: 1;
  transform: none;
  animation: none;
}

/* ── Toast / notification slide ──────────────────────────── */

.toast-enter {
  transform: translateY(calc(100% * var(--motion-scale))) scale(calc(1 - 0.05 * var(--motion-scale)));
  opacity: 0;
}

.toast-enter-active {
  transform: translateY(0) scale(1);
  opacity: 1;
  transition: transform var(--motion-duration-slow) var(--motion-easing-spring),
              opacity var(--motion-duration-normal) var(--motion-easing);
}

.toast-exit-active {
  transform: translateX(calc(100% * var(--motion-scale)));
  opacity: 0;
  transition: transform var(--motion-duration-normal) var(--motion-easing-in),
              opacity var(--motion-duration-fast) var(--motion-easing);
}

/* ═══════════════════════════════════════════════════════════════
   Global Motion System (added 2026-05-11)
   Three tiers applied automatically — no class wiring required.
   GPU-composited (transform + opacity only). Targets Linear/Vercel feel.
   ═══════════════════════════════════════════════════════════════ */

:root {
  --ss-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ss-dur-micro: 100ms;
  --ss-dur-meso:  180ms;
  --ss-dur-macro: 250ms;
}

html[data-motion="subtle"] {
  --ss-dur-micro: 60ms;
  --ss-dur-meso:  120ms;
  --ss-dur-macro: 180ms;
}

html[data-motion="reduced"] {
  --ss-dur-micro: 0ms;
  --ss-dur-meso:  0ms;
  --ss-dur-macro: 0ms;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --ss-dur-micro: 0ms;
    --ss-dur-meso:  0ms;
    --ss-dur-macro: 0ms;
  }
}

/* ── Micro tier — buttons, toggles, chips, icons ───────────── */
button,
.btn,
[role="button"],
input[type="button"],
input[type="submit"],
input[type="reset"] {
  transition: transform var(--ss-dur-micro) var(--ss-ease),
              background-color var(--ss-dur-micro) var(--ss-ease),
              border-color var(--ss-dur-micro) var(--ss-ease),
              box-shadow var(--ss-dur-micro) var(--ss-ease),
              color var(--ss-dur-micro) var(--ss-ease);
}

button:not(:disabled):active,
.btn:not(:disabled):active,
[role="button"]:not([aria-disabled="true"]):active,
input[type="button"]:not(:disabled):active,
input[type="submit"]:not(:disabled):active,
input[type="reset"]:not(:disabled):active {
  transform: scale(calc(1 - 0.03 * var(--motion-scale, 1)));
}

/* ── Meso tier — clickable cards lift on hover ─────────────── */
.ct-card,
.prj-strip-card,
.fin-strip-card,
.raid-card,
.ppl-summary-card,
.summary-card,
.metric-card,
.dashboard-card,
.kpi-card,
.act-card,
.proj-card,
.proj-row-card,
.tower-card {
  transition: transform var(--ss-dur-meso) var(--ss-ease),
              box-shadow var(--ss-dur-meso) var(--ss-ease),
              border-color var(--ss-dur-meso) var(--ss-ease);
  will-change: transform;
}

@media (hover: hover) {
  .ct-card:hover,
  .prj-strip-card:hover,
  .fin-strip-card:hover,
  .raid-card:hover,
  .ppl-summary-card:hover,
  .summary-card:hover,
  .metric-card:hover,
  .dashboard-card:hover,
  .kpi-card:hover,
  .act-card:hover,
  .proj-card:hover,
  .proj-row-card:hover,
  .tower-card:hover {
    transform: translateY(calc(-2px * var(--motion-scale, 1)));
    box-shadow: 0 4px 12px rgba(0, 0, 0, calc(0.08 * var(--motion-scale, 1)));
  }
}

.ct-card:active,
.prj-strip-card:active,
.fin-strip-card:active,
.raid-card:active,
.ppl-summary-card:active,
.summary-card:active,
.metric-card:active,
.dashboard-card:active,
.kpi-card:active,
.act-card:active,
.proj-card:active,
.proj-row-card:active,
.tower-card:active {
  transform: translateY(0);
  box-shadow: 0 1px 3px rgba(0, 0, 0, calc(0.06 * var(--motion-scale, 1)));
}

/* ── Table rows — universal background tween ───────────────── */
tbody tr,
.ct-sec-row,
.prj-row,
.raid-row,
.fin-row,
.ppl-row,
.act-row {
  transition: background-color var(--ss-dur-meso) var(--ss-ease),
              border-color var(--ss-dur-meso) var(--ss-ease);
}

/* ── Tabs — active indicator slide ─────────────────────────── */
.tabs__indicator,
.tab-indicator,
[data-role="tab-indicator"] {
  transition: left var(--ss-dur-meso) var(--ss-ease),
              width var(--ss-dur-meso) var(--ss-ease),
              transform var(--ss-dur-meso) var(--ss-ease);
}

/* ── Nav items — hover slide ───────────────────────────────── */
.nav__link {
  transition: background-color var(--ss-dur-micro) var(--ss-ease),
              color var(--ss-dur-micro) var(--ss-ease),
              transform var(--ss-dur-micro) var(--ss-ease);
}

@media (hover: hover) {
  .nav__link:hover:not(.nav__link--active) {
    transform: translateX(calc(2px * var(--motion-scale, 1)));
  }
}

/* ── Dropdowns / menus — open animation ────────────────────── */
[data-open="true"].dropdown,
[data-open="true"].topbar__menu,
.dropdown[data-open="true"],
.topbar__menu[data-open="true"],
.ss-menu[data-open="true"],
.menu[data-open="true"] {
  animation: ss-menu-open var(--ss-dur-meso) var(--ss-ease);
}

@keyframes ss-menu-open {
  from {
    opacity: 0;
    transform: translateY(calc(-4px * var(--motion-scale, 1)));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ── Modal / dialog — open animation ───────────────────────── */
.modal-overlay[data-open="true"],
.ss-modal-overlay[data-open="true"],
dialog[open] {
  animation: ss-overlay-in var(--ss-dur-macro) var(--ss-ease);
}

.modal[data-open="true"],
.ss-modal[data-open="true"],
dialog[open] > * {
  animation: ss-dialog-in var(--ss-dur-macro) var(--ss-ease);
}

@keyframes ss-overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes ss-dialog-in {
  from {
    opacity: 0;
    transform: scale(calc(1 - 0.02 * var(--motion-scale, 1)));
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* ── Toast / notification — top-bar style enter ────────────── */
.ss-toast,
.toast {
  animation: ss-toast-in var(--ss-dur-macro) var(--ss-ease);
}

@keyframes ss-toast-in {
  from {
    opacity: 0;
    transform: translateY(calc(-8px * var(--motion-scale, 1)));
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ── Page transitions — driven by shell-router.js ──────────── */
#mount {
  transition: opacity var(--ss-dur-macro) var(--ss-ease),
              transform var(--ss-dur-macro) var(--ss-ease);
  will-change: opacity, transform;
}

#mount.ss-page-exit {
  opacity: 0;
  transform: translateY(calc(4px * var(--motion-scale, 1)));
}

#mount.ss-page-enter {
  opacity: 0;
  transform: translateY(calc(-4px * var(--motion-scale, 1)));
}

/* Defensive: never let page transitions interfere with print. */
@media print {
  #mount,
  #mount.ss-page-exit,
  #mount.ss-page-enter {
    transition: none;
    transform: none;
    opacity: 1;
  }
}

/* ═══════════════════════════════════════════════════════════════
   Gratification Layer (added 2026-05-24)
   Microinteraction rewards driven by components_vnext/gratification.js.
   Movement = transform + opacity (GPU). Colour cues = box-shadow /
   border-color (paint only, no layout reflow). Calm curve, no
   spring/bounce. Durations slot into the 3-tier system and collapse to
   0ms under reduced motion.
   ═══════════════════════════════════════════════════════════════ */

:root {
  --grat-ease: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --grat-dur-press:    90ms;   /* micro — button press            */
  --grat-dur-error:    200ms;  /* micro/meso — validation shake    */
  --grat-dur-reveal:   150ms;  /* meso  — content entry            */
  --grat-dur-complete: 200ms;  /* meso  — completion pulse         */
  --grat-dur-delete:   200ms;  /* meso  — row shrink + fade        */
  --grat-dur-save:     300ms;  /* macro — save flash               */
  --grat-dur-drag:     250ms;  /* macro — drag elevate / settle    */
}

html[data-motion="subtle"] {
  --grat-dur-press:    60ms;
  --grat-dur-error:    140ms;
  --grat-dur-reveal:   120ms;
  --grat-dur-complete: 140ms;
  --grat-dur-delete:   140ms;
  --grat-dur-save:     200ms;
  --grat-dur-drag:     180ms;
}

html[data-motion="reduced"] {
  --grat-dur-press:    0ms;
  --grat-dur-error:    0ms;
  --grat-dur-reveal:   0ms;
  --grat-dur-complete: 0ms;
  --grat-dur-delete:   0ms;
  --grat-dur-save:     0ms;
  --grat-dur-drag:     0ms;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --grat-dur-press:    0ms;
    --grat-dur-error:    0ms;
    --grat-dur-reveal:   0ms;
    --grat-dur-complete: 0ms;
    --grat-dur-delete:   0ms;
    --grat-dur-save:     0ms;
    --grat-dur-drag:     0ms;
  }
}

/* ── onAction — physical press ─────────────────────────────────── */
@keyframes grat-action {
  0%   { transform: scale(1); }
  45%  { transform: scale(0.96); }
  100% { transform: scale(1); }
}
.grat-action {
  animation: grat-action var(--grat-dur-press) var(--grat-ease);
  will-change: transform;
}

/* ── onComplete — scale pulse + green glow fade ────────────────── */
@keyframes grat-complete {
  0%   { transform: scale(1);     box-shadow: 0 0 0 0 transparent; }
  35%  { transform: scale(1.035); box-shadow: 0 0 0 4px var(--color-green-light, rgba(39, 174, 96, .12)); }
  100% { transform: scale(1);     box-shadow: 0 0 0 0 transparent; }
}
.grat-complete {
  animation: grat-complete var(--grat-dur-complete) var(--grat-ease);
  will-change: transform;
}

/* ── onSave — soft green border ring, fades over 300ms ─────────── */
@keyframes grat-save {
  0%   { box-shadow: inset 0 0 0 0 transparent; }
  18%  { box-shadow: inset 0 0 0 2px var(--color-green, #1E8449); }
  100% { box-shadow: inset 0 0 0 0 transparent; }
}
.grat-save {
  animation: grat-save var(--grat-dur-save) var(--grat-ease);
}

/* ── onError — 2px horizontal shake + red border ───────────────── */
@keyframes grat-error {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-2px); }
  40%      { transform: translateX(2px); }
  60%      { transform: translateX(-2px); }
  80%      { transform: translateX(2px); }
}
.grat-error {
  animation: grat-error var(--grat-dur-error) var(--grat-ease);
  box-shadow: 0 0 0 2px var(--color-red-light, rgba(192, 57, 43, .25));
  border-color: var(--color-red, #C0392B);
  will-change: transform;
}

/* ── onReveal — opacity + lift entry ───────────────────────────── */
@keyframes grat-reveal {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.grat-reveal {
  animation: grat-reveal var(--grat-dur-reveal) var(--grat-ease) both;
  will-change: transform, opacity;
}

/* ── onDelete — shrink + fade out, holds final state ───────────── */
@keyframes grat-delete {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(0.96); }
}
.grat-delete {
  animation: grat-delete var(--grat-dur-delete) var(--grat-ease) forwards;
  pointer-events: none;
  will-change: transform, opacity;
}

/* ── onDrag — weighted pickup + smooth settle ──────────────────── */
.grat-dragging {
  transform: rotate(0.6deg) scale(1.01);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14);
  transition: transform var(--grat-dur-drag) var(--grat-ease),
              box-shadow var(--grat-dur-drag) var(--grat-ease);
  position: relative;
  z-index: 2;
}
.grat-drag-settle {
  transition: transform var(--grat-dur-drag) var(--grat-ease),
              box-shadow var(--grat-dur-drag) var(--grat-ease);
}

/* ── onProgress — eased fill + leading-edge shimmer ────────────── */
.grat-progress {
  transition: width var(--grat-dur-save) var(--grat-ease);
  position: relative;
  overflow: hidden;
}
.grat-progress--shimmer::after {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: 24px;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.45));
  animation: grat-progress-shimmer 0.6s var(--grat-ease);
}
@keyframes grat-progress-shimmer {
  from { opacity: 0; transform: translateX(8px); }
  50%  { opacity: 1; }
  to   { opacity: 0; transform: translateX(0); }
}

/* ── Global button press feel — every primary/secondary button ───
   Covers single-dash (ui/core.css) + BEM (components.css) variants and
   non-<button> elements styled as buttons. <button>/.btn already get a
   press via the Micro tier above; this extends it to the class set the
   app uses for CTAs. */
.btn-primary, .btn-secondary,
.btn--primary, .btn--secondary {
  transition: transform var(--grat-dur-press) var(--grat-ease),
              background-color var(--grat-dur-press) var(--grat-ease),
              border-color var(--grat-dur-press) var(--grat-ease),
              box-shadow var(--grat-dur-press) var(--grat-ease),
              color var(--grat-dur-press) var(--grat-ease);
}
.btn-primary:not(:disabled):active,
.btn-secondary:not(:disabled):active,
.btn--primary:not(:disabled):active,
.btn--secondary:not(:disabled):active {
  transform: scale(calc(1 - 0.04 * var(--motion-scale, 1)));
}
