/* MOTION SYSTEM
   Token layer and base rules: three curves, a six-step duration ladder, four scales, one stagger beat.
   Any property may animate; every transition takes its duration and curve from here, and a raw easing or
   duration in styles.css is a lint failure.

   Choosing values:
   - Duration follows size, and exits run shorter than entrances.
   - Ease out for anything entering or leaving; ease in-out only for changes that stay in place.
   - Scale follows size the other way: small things can scale more, large things less, exits least.
   - Movement uses the spacing scale: --size-xs for text swaps, --size-sm for page-level shifts,
     --size-sm to --size-xl for most elements. */

:root {
  /* CURVES */
  --ease-out-cubic:   cubic-bezier(0.215, 0.61, 0.355, 1);   /* Default. Anything entering or leaving: starts quick, settles gently. */
  --ease-out-expo:    cubic-bezier(0.19, 1, 0.22, 1);        /* Smooth ease-out: an even quicker start and a longer settle, for large travel and showpiece reveals. */
  --ease-in-out-sine: cubic-bezier(0.445, 0.05, 0.55, 0.95); /* In-place changes only: hover tints, colour and opacity crossfades. */

  /* DURATIONS — a ladder sized to the thing that moves. */
  --dur-instant: 0.1s;   /* Changes in place that shouldn't draw the eye: hover tints, focus rings, colour shifts. */
  --dur-small:   0.15s;  /* Small elements and quick feedback: button presses, tooltips, small icon swaps. */
  --dur-fast:    0.25s;  /* Medium elements (menus, dropdowns, tabs) and the exit of anything larger. */
  --dur-base:    0.4s;   /* Large elements arriving: panels, dialogs, drawers, a code window opening. */
  --dur-slow:    0.6s;   /* Page-scale changes: the dissolve between pages. */
  --dur-slower:  1.4s;   /* Expressive scroll-driven travel: section reveals and showpiece moments. */

  /* SCALE — the size an element starts from (or ends at) when it scales into place. */
  --scale-small: 0.96;   /* Small elements: presses, tooltips, chips. */
  --scale-large: 0.98;   /* Large elements arriving: dialogs, panels, the lightbox. */
  --scale-exit:  0.99;   /* Large elements leaving: barely there, the element is already understood. */
  --scale-hover: 1.04;   /* A slight lift on hover for things that open. */

  /* STAGGER — one beat, multiplied by an --index the markup sets on each child. */
  --beat:      0.1s;     /* Gap between siblings entering in sequence. */
  --beat-lead: 0.2s;     /* Wait before the first sibling, so a sequence starts after the page settles. */

  /* PAGE TRANSITION */
  --view-transition-duration: var(--dur-slow);           /* The page-to-page dissolve. */
  --view-transition-easing:   cubic-bezier(0.5, 0.3, 0, 1); /* Its curve: a slow start into a long, soft finish. */

  /* COMPOSITES — show and hide in one declaration. Hiding is quicker than appearing; visibility flips at once
     on appear. */
  --appear: transform var(--dur-fast) var(--ease-out-expo),
            opacity var(--dur-instant) var(--ease-in-out-sine) 0s,
            visibility var(--dur-instant) 0s;
  --hide:   transform var(--dur-instant) var(--ease-out-cubic),
            opacity var(--dur-instant) var(--ease-in-out-sine),
            visibility var(--dur-instant);
}

/* BASE RULES */

/* Reveal: opacity resolves in half the time the travel takes, so nothing lands with a thud. */
.reveal {
  opacity: 0;
  transform: translateY(var(--size-lg));
  transition: opacity var(--dur-slow) var(--ease-in-out-sine),
              transform var(--dur-slower) var(--ease-out-expo);
  transition-delay: calc(var(--index, 0) * var(--beat) + var(--beat-lead));
}

.reveal[data-revealed="true"] {
  opacity: 1;
  transform: translateY(0);
}

/* Explicit opt-out. Killing a transition is a declaration, not an omission. */
.motion-none {
  transition: 0s;
}

/* PAGE TRANSITIONS — the outgoing page dissolves into the page colour, then the incoming page dissolves in. Nothing shows through. */
@view-transition { navigation: auto; }

/* The whole transition overlay is the page colour, not just the image pair, so no frame of it can fall through to white. */
::view-transition {
  background-color: var(--color-surface-default);
}

::view-transition-group(*) {
  animation-duration: var(--view-transition-duration);
  animation-timing-function: var(--view-transition-easing);
}

::view-transition-image-pair(root) {
  isolation: auto;
  background-color: var(--color-surface-default);
}

::view-transition-old(root),
::view-transition-new(root) {
  mix-blend-mode: normal;
}

::view-transition-old(root) {
  animation: old-page var(--view-transition-duration) var(--ease-in-out-sine) both;
}

::view-transition-new(root) {
  animation: new-page var(--view-transition-duration) var(--ease-in-out-sine) calc(var(--view-transition-duration) / 2) both;
}

@keyframes old-page {
  from { opacity: 1; }
  to   { opacity: 0; }
}

@keyframes new-page {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* REDUCED MOTION — collapse the ladder rather than delete motion: short feedback survives, travel does not. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: 0.01s;
    --dur-small:   0.01s;
    --dur-fast:    0.01s;
    --dur-base:    0.01s;
    --dur-slow:    0.01s;
    --dur-slower:  0.01s;
    --beat:        0s;
    --beat-lead:   0s;
    --view-transition-duration: 0.01s;
  }

  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }

  .reveal { transform: none; }
}
