/* ===========================================================================
   motion.css — every keyframe on the site, in one file.

   Two moments only:
     1. The load sequence on Home. A rule sweeps the full width and the name
        is wiped in behind it; everything else settles in its wake. One
        gesture, not eight separate reveals.
     2. The summary sheet growing out of the corner button that opened it.

   Deliberately absent: fade-up-on-scroll, hover lift, parallax.
   =========================================================================== */

@keyframes sweep {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

@keyframes unveil {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

@keyframes settle {
  from { opacity: 0; transform: translateY(7px); }
  to   { opacity: 1; transform: none; }
}

@keyframes doorIn {
  from { opacity: 0; transform: translateY(18px) scale(0.92); }
  to   { opacity: 1; transform: none; }
}

@keyframes scrimIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Opening the corner door. The button is the hinge: the panel starts the size
   of the button, at the button, and grows out of it — so the gesture reads as
   "this was tucked away" rather than "this is a new page". app.js measures the
   button against the panel and fills in the origin and the two scales before
   the first paint, so the panel begins as the button's own rectangle; without
   it the panel simply appears. Closing runs the same path backwards, not a
   cut. */
@keyframes doorOpen {
  from { opacity: 0; transform: scale(var(--door-sx, 0.14), var(--door-sy, 0.09)); }
  28%  { opacity: 1; }
  to   { opacity: 1; transform: none; }
}

@keyframes doorShut {
  from { opacity: 1; transform: none; }
  72%  { opacity: 1; }
  to   { opacity: 0; transform: scale(var(--door-sx, 0.14), var(--door-sy, 0.09)); }
}

/* Text cannot be scaled up from a sixth of its size without looking rubbery,
   so the contents arrive once the panel is most of the way there. */
@keyframes contentsIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* --- the load sequence ---------------------------------------------------- */

.lead-rule      { transform-origin: left; animation: sweep 0.8s cubic-bezier(0.22, 1, 0.36, 1) both; }
.lead-name      { animation: unveil 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.06s both; }
.lead-identity  { animation: settle 0.5s ease-out 0.55s both; }
.lead-summary   { animation: settle 0.5s ease-out 0.68s both; }
.lead-education { animation: settle 0.5s ease-out 0.80s both; }
.lead-nav       { animation: settle 0.5s ease-out 0.92s both; }
/* backwards, not both: once it has sprung in, the button goes back to being
   governed by ordinary rules, so it can transition out of the way when the
   panel opens. A filled animation would outrank them. */
.lead-door      { animation: doorIn 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) 1.10s backwards; }

/* Inner pages get the same settle, without the sweep. */
.enter     { animation: settle 0.5s ease-out both; }
.enter-1   { animation: settle 0.5s ease-out 0.10s both; }
.enter-2   { animation: settle 0.5s ease-out 0.18s both; }
.enter-3   { animation: settle 0.5s ease-out 0.26s both; }

/* --- the summary sheet ---------------------------------------------------- */

.glance-scrim { animation: scrimIn 0.32s ease-out both; }
.glance-sheet { transform-origin: var(--door-x, 50%) var(--door-y, 50%); }
/* A gentler ease-out than the rest of the site uses. The usual curve is so
   front-loaded that the panel would be near full size within 100ms and the
   growth would not read at all. */
.glance-sheet[data-door="open"] { animation: doorOpen 0.46s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
.glance-sheet[data-door="open"] > * { animation: contentsIn 0.26s ease-out 0.2s both; }

.glance-overlay[data-closing="true"] .glance-scrim { animation: scrimIn 0.24s ease-in reverse both; }
.glance-overlay[data-closing="true"] .glance-sheet[data-door="open"] {
  animation: doorShut 0.26s cubic-bezier(0.4, 0, 1, 1) both;
}
.glance-overlay[data-closing="true"] .glance-sheet > * { animation: none; opacity: 1; }

/* --- the button ----------------------------------------------------------- */
/* One idea, used on every button: the fill rises from the bottom edge,
   starting under the pointer. The label never changes colour.            */

.btn::before {
  content: "";
  position: absolute;
  left: var(--press-x, 50%);
  bottom: 0;
  width: 0;
  height: 0;
  transform: translateX(-50%);
  background: var(--btn-fill, var(--signal));
  border-radius: 50% 50% 0 0;
  transition: width 0.34s cubic-bezier(0.22, 1, 0.36, 1),
              height 0.34s cubic-bezier(0.22, 1, 0.36, 1),
              border-radius 0.34s ease;
  z-index: -1;
}

.btn:hover::before,
.btn:focus-visible::before {
  width: 260%;
  height: 260%;
  border-radius: 0;
}

.btn:active {
  transform: translateY(2px);
}

/* --- always ---------------------------------------------------------------
   Every animation above has a static finished state, so switching them off
   never leaves a layout half-built.                                       */

/* Flipping the switch. The attribute is on for a third of a second either side
   of the change and then removed, so the whole page crosses over together
   instead of snapping — and so nothing else on the site pays for a transition
   it never uses. The reduce block below removes it along with everything else. */
:root[data-theme-shift] *,
:root[data-theme-shift] *::before,
:root[data-theme-shift] *::after {
  transition-property: background-color, border-color, color, fill, box-shadow !important;
  transition-duration: 0.32s !important;
  transition-timing-function: ease !important;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .btn::before { display: none; }
  .btn:hover,
  .btn:focus-visible { background: var(--btn-fill, var(--signal)); }
}
