/* ---------------------------------------------------------------------------
   motion.css — the site's motion foundation. Loaded by EVERY page, Framer-
   exported and store alike, so both pipelines animate with one vocabulary.

   Structure (read this before adding anything):

   1. TOKENS      all durations/easings live here as custom properties. New
                  animation work uses tokens, never literal ms/bezier values —
                  that's what keeps the site feeling like one piece.
   2. NAV         state classes for the hide/show nav. JS (motion.js) only
                  flips `m-nav-hidden` on <html>; every visual consequence is
                  CSS, so restyling the gesture never touches logic.
   3. REVEAL      scroll-in for generated pages ([data-mreveal]). Framer pages
                  keep their own [data-reveal] path in runtime.js — untouched.
   4. TRANSITIONS cross-document view transitions. Pure CSS; pages opt in by
                  carrying this stylesheet. Elements gain continuity by getting
                  a `view-transition-name` — see store.mjs for the card→product
                  morph, and motion.js for the nav.

   The easing values are not invented: they were read out of Framer's own
   published bundles (see src/client/runtime.js) so new motion matches the
   original site's physics.
   --------------------------------------------------------------------------- */

:root {
  /* durations */
  --m-dur-1: 200ms;   /* micro: hovers, presses, small fades          */
  --m-dur-2: 420ms;   /* structural: nav slide, panel moves           */
  --m-dur-3: 800ms;   /* entrances: reveals — Framer's own 0.8s       */

  /* easings — measured from Framer's bundles */
  --m-ease:        cubic-bezier(.44, 0, .56, 1);      /* standard tween    */
  --m-ease-exit:   cubic-bezier(.32, -.01, .15, .98); /* intro/exit curve  */
  --m-ease-spring: cubic-bezier(.34, 1.26, .64, 1);   /* hover spring ≈ bounce .2 */

  /* reveal geometry */
  --m-rise: 24px;

  /* nav thresholds are JS constants (motion.js), not CSS — they're inputs,
     not styles. Only the *response* lives here. */
}

/* --- 2. nav ---------------------------------------------------------------- */

/* The wrapper is tagged data-site-nav — at build time on store pages, by
   motion.js on Framer pages (it finds the pinned container at runtime, so a
   re-export from Framer can't silently orphan a hardcoded selector).

   `translate` (not `transform`) on purpose: Framer centres fixed elements with
   transform, and the individual property composes with it instead of clobbering. */
/* The attribute is doubled on purpose. Framer styles this element through
   `.framer-raLMF .framer-5ozm90-container` — two classes — so a single
   attribute selector loses and the z-index below silently did nothing.
   Doubling matches that specificity and wins on order, which beats !important:
   a later rule can still override this one normally. */
[data-site-nav][data-site-nav] {
  transition:
    translate var(--m-dur-2) var(--m-ease),
    opacity   var(--m-dur-2) var(--m-ease);

  /* Above everything. Framer gave the nav z-index 8, but the home <header>
     opens its own stacking context at z-index 7 one level up — so the pointer
     trail living inside that header painted straight over the menu. The nav is
     the one element that must never be covered; pinning it here also protects
     it from whatever overlay comes next. */
  z-index: 50;
}

/* -100% clears the element itself; the extra 80px clears Framer's `top: 50px`
   offset too, so it leaves the viewport instead of resting just off the edge. */
html.m-nav-hidden [data-site-nav][data-site-nav] {
  translate: 0 calc(-100% - 80px);
  opacity: 0;
  pointer-events: none;
}

/* Case pages keep FEL/WORK/ABOUT + accordion on screen for the mosaic scroll.
   copy.css repeats this so it wins even if motion.css loads first. */
html.m-nav-hidden body[data-project-page] [data-site-nav][data-site-nav] {
  translate: none;
  opacity: 1;
  pointer-events: auto;
}

/* --- 3. reveal ------------------------------------------------------------- */

/* Armed by JS only for elements that start below the fold — content is never
   hidden by default, so no-JS and reduced-motion users see everything, always.
   Removing the attribute plays the entrance. Same arming pattern as runtime.js. */
[data-mreveal] {
  transition:
    opacity   var(--m-dur-3) var(--m-ease),
    transform var(--m-dur-3) var(--m-ease);
}

[data-mreveal][data-mreveal-armed] {
  opacity: 0;
  transform: translateY(var(--m-rise));
}

/* --- 4. cross-document view transitions ------------------------------------ */

/* Catalogue ↔ product is a dissolve, not a morph: a 3× scale from card to
   stage (and back) reads as a jump. The photo only keeps a name on the
   product hero and the editor canvas, whose boxes already match — so
   Edit online holds the shot still. Nav is named on every page and stays.
   Browsers without support just navigate. */
@view-transition { navigation: auto; }

/* Old page stays put; the new one fades in on top. Overlapping two
   50% fades on black dips to grey in the middle — that's the tosca bit. */
::view-transition-old(root) {
  animation: none;
}
::view-transition-new(root) {
  animation: m-vt-in var(--m-dur-1) var(--m-ease) both;
}
@keyframes m-vt-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

::view-transition-group(site-nav) {
  z-index: 50;
  animation: none;
}

/* Product ↔ editor: same rectangle, so don't interpolate size. */
html::view-transition-group(.mockup-shot) {
  animation: none;
}
html::view-transition-old(.mockup-shot),
html::view-transition-new(.mockup-shot) {
  object-fit: contain;
  object-position: top center;
  overflow: clip;
}

.st-vt,
canvas#cv {
  view-transition-class: mockup-shot;
}

/* --- reduced motion --------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  [data-site-nav],
  [data-mreveal] {
    transition: none;
  }
  [data-mreveal][data-mreveal-armed] {
    opacity: 1;
    transform: none;
  }
  @view-transition { navigation: none; }
}

/* --- smooth anchors ---------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* --- /projects loader + row entrance -------------------------------------- */

/* Synthetic DESIGN by FEL curtain. Injected only on /projects (no nQ9AK).
   First-paint brown lives in the boot <style> in transform.mjs; this is the
   sequence: words rise, curtain scaleY(0) from the top, same tokens as home. */
#fel-loader {
  position: fixed;
  inset: 0;
  z-index: 80;
  pointer-events: auto;
  background: var(--c-brown, #2b1b0d);
}
#fel-loader.is-ready {
  background: transparent;
}
.fel-loader-curtain {
  position: absolute;
  inset: 0;
  background: var(--c-brown, #2b1b0d);
  transform-origin: 50% 0%;
}
.fel-loader-words {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  z-index: 2;
  overflow: hidden;
  pointer-events: none;
}
.fel-loader-clip {
  display: block;
  overflow: hidden;
  line-height: 1;
}
.fel-loader-word {
  display: block;
  font-family: 'Maxeville Construct', 'Maxeville Regular', sans-serif;
  font-size: clamp(36px, 10vw, 79px);
  color: #fff;
  line-height: 1;
  white-space: nowrap;
  transform: translateY(100%);
}
#fel-loader.is-arrive .fel-loader-word {
  transform: translateY(0);
  transition: transform var(--m-dur-3) var(--m-ease);
}
#fel-loader.is-arrive .fel-loader-clip:nth-child(2) .fel-loader-word {
  transition-delay: 110ms;
}
#fel-loader.is-arrive .fel-loader-clip:nth-child(3) .fel-loader-word {
  transition-delay: 220ms;
}
#fel-loader.is-leave.is-arrive .fel-loader-word,
#fel-loader.is-leave .fel-loader-word {
  transform: translateY(-110%);
  transition: transform 1000ms var(--m-ease-exit);
}
#fel-loader.is-leave .fel-loader-curtain {
  transform: scaleY(0);
  transition: transform 1000ms var(--m-ease-exit);
}

html:not(.fel-intro-done) body[data-projects-page] {
  overflow: hidden;
}

/* Rows hold still under the curtain, then ease in with the reveal vocabulary. */
body[data-projects-page] a[data-project-name] {
  transition:
    opacity var(--m-dur-3) var(--m-ease) var(--fel-row-delay, 0ms),
    transform var(--m-dur-3) var(--m-ease) var(--fel-row-delay, 0ms);
}
body[data-projects-page] a[data-project-name][data-fel-row-armed] {
  opacity: 0;
  transform: translateY(var(--m-rise));
}

@media (prefers-reduced-motion: reduce) {
  #fel-loader {
    display: none !important;
  }
  html:not(.fel-intro-done) body[data-projects-page] {
    overflow: auto;
  }
  body[data-projects-page] a[data-project-name],
  body[data-projects-page] a[data-project-name][data-fel-row-armed] {
    transition: none;
    opacity: 1;
    transform: none;
  }
}
