/* effects.css — Studio Chaukhat
   Four motion techniques for the WHOLE site, reused on every page. No new
   gimmick per page.

   1 · THE THRESHOLD OPENS  (first-timer, and the signature element)
       Every photograph starts clipped to a narrow centre slot; the doorframe
       draws downward and the aperture opens as the plate enters view.
   2 · THE PROJECTION SCRUB (first-timer)
       Scroll position through the projection section drives PLAN → ELEVATION
       → SECTION as one continuous morph.
   3 · STAGGERED REVEAL     (entrance treatment)
       Text blocks rise a few pixels, one after another. Same curve as
       everything else.
   4 · THE JAMB HOVER       (interaction system, defined in style.css)
       A vermillion rule grows across the top of a link, like a lintel.

   Every closed / hidden start state below is gated behind `html.js.motion`.
   main.js adds `js` always and `motion` only when the visitor has NOT asked
   for reduced motion — so with no JavaScript, or with reduced motion on,
   the page renders in its finished state with nothing hidden.
*/

/* ─────────────────────────────────────────────────────────────────────
   1 · THE THRESHOLD OPENS
   ───────────────────────────────────────────────────────────────────── */

/* `data-armed` is added by animations.js, never authored in the markup — so a
   page that never runs JS has no closed state to get stuck in, and an image
   is never painted closed before the script has had a chance to open it. */
html.js.motion .threshold[data-armed] .threshold__pane img {
  clip-path: inset(0 43% 0 43%);
  transition: clip-path 1s var(--ease-door), filter 1s var(--ease-door);
  filter: saturate(0.4) contrast(1.03);
}
html.js.motion .threshold[data-armed] .threshold__frame {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 0.72s var(--ease-door) 0.06s;
}
html.js.motion .threshold[data-armed] .threshold__caption {
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.5s var(--transition) 0.5s, transform 0.5s var(--transition) 0.5s;
}

html.js.motion .threshold.is-open .threshold__pane img {
  clip-path: inset(0 0 0 0);
  filter: saturate(0.86) contrast(1.03);
}
html.js.motion .threshold.is-open .threshold__frame { clip-path: inset(0 0 0 0); }
html.js.motion .threshold.is-open .threshold__caption { opacity: 1; transform: none; }

/* ─────────────────────────────────────────────────────────────────────
   2 · THE PROJECTION SCRUB
   Base layout (no JS / reduced motion) is a static three-up row of three
   complete drawings — see style.css §11. Only when JS and motion are both
   available do the layers stack into one scrubbed aperture.
   ───────────────────────────────────────────────────────────────────── */

html.js.motion .proj__stage {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
}
html.js.motion .proj__layer {
  grid-area: 1 / 1;
  border-top: 0;
  padding-top: 0;
  opacity: var(--p, 0);
  transform: translateY(calc((1 - var(--p, 0)) * 10px));
  transition: opacity 0.18s linear, transform 0.18s linear;
  pointer-events: none;
}
/* Linework may overlap mid-scrub — two orthographic views of the same house
   superimposed is exactly what a projection overlay looks like. Labels must
   NOT: they are raised to the fourth power so only the dominant drawing is
   ever captioned, and the crossover reads as line on line, not text on text. */
html.js.motion .proj__layer .proj__note {
  opacity: calc(var(--p, 0) * var(--p, 0) * var(--p, 0) * var(--p, 0));
}
html.js.motion .proj__layer .proj__tag,
html.js.motion .proj__layer .proj__sub {
  opacity: calc(var(--p, 0) * var(--p, 0) * var(--p, 0));
  transition: opacity 0.18s linear;
}
html.js.motion .proj__layer .proj__poche {
  opacity: calc(var(--p, 0) * var(--p, 0));
}
html.js.motion .proj__index { pointer-events: none; }

/* The drawn lines settle in as the layer becomes the active one. */
html.js.motion .proj__layer .proj__mark {
  stroke-dasharray: 220;
  stroke-dashoffset: calc((1 - var(--p, 0)) * 220);
  transition: stroke-dashoffset 0.28s linear;
}

/* ─────────────────────────────────────────────────────────────────────
   3 · STAGGERED REVEAL
   ───────────────────────────────────────────────────────────────────── */

html.js.motion .reveal-item {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.62s var(--ease-door), transform 0.62s var(--ease-door);
}
html.js.motion .reveal-item.is-in { opacity: 1; transform: none; }

/* Stagger is applied by animations.js as a transition-delay custom property. */
html.js.motion .reveal-item { transition-delay: var(--d, 0ms); }

/* ─────────────────────────────────────────────────────────────────────
   4 · MOBILE NAV — the panel opens like a door leaf
   ───────────────────────────────────────────────────────────────────── */

/* Gated on `html.js`: without JavaScript there is no button to open this
   panel, so the nav must stay in the flow rather than hide off-screen. */
html.js .nav {
  position: fixed;
  inset: auto 0 0 0;
  top: var(--nav-top, 3.5rem);
  z-index: 55;
  width: auto;
  background: var(--color-bg);
  border-top: var(--jamb-rule) solid var(--color-rule);
  padding: var(--space-lg) var(--gutter) 6rem;
  transform-origin: top;
  visibility: hidden;
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity 0.28s var(--ease-door), transform 0.28s var(--ease-door), visibility 0s linear 0.28s;
  overflow-y: auto;
}
html.js .nav.is-open {
  visibility: visible;
  opacity: 1;
  transform: none;
  transition: opacity 0.32s var(--ease-door), transform 0.32s var(--ease-door), visibility 0s;
}
html.js .nav .nav__list { flex-direction: column; gap: 0; }
html.js .nav .nav__link {
  display: block;
  font-size: var(--text-2xl);
  letter-spacing: 0.01em;
  padding-block: 0.65rem;
  border-bottom: var(--jamb-rule) solid var(--color-hair);
}
html.js .nav .nav__link::before { height: 3px; }
html.js .nav .nav__foot {
  display: block;
  margin-top: var(--space-lg);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  line-height: 2;
}
html.js .nav .nav__foot a { border-bottom: var(--jamb-rule) solid var(--color-border); }

body.nav-locked { overflow: hidden; }

/* ─────────────────────────────────────────────────────────────────────
   5 · IMAGE HOVER — one system, shared by every aperture
   ───────────────────────────────────────────────────────────────────── */

.threshold__pane img { transition: transform 0.7s var(--ease-door), filter 0.7s var(--ease-door); }
@media (hover: hover) and (pointer: fine) {
  .entry:hover .threshold__pane img,
  .plate:hover .threshold__pane img { transform: scale(1.028); }
  .entry:hover .threshold__frame,
  .plate:hover .threshold__frame { border-color: var(--color-accent); }
}
.threshold__frame { transition: border-color var(--transition); }

/* ─────────────────────────────────────────────────────────────────────
   6 · REDUCED MOTION — mandatory. Everything lands in its finished state.
   ───────────────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  .threshold .threshold__pane img { clip-path: none !important; filter: saturate(0.86) contrast(1.03) !important; transform: none !important; }
  .threshold .threshold__frame    { clip-path: none !important; }
  .threshold .threshold__caption  { opacity: 1 !important; transform: none !important; }

  .reveal-item { opacity: 1 !important; transform: none !important; }

  /* The projection set returns to a static, complete three-up row. */
  .proj__stage { display: grid !important; grid-template-columns: 1fr !important; gap: var(--space-md) !important; }
  .proj__layer {
    grid-area: auto !important;
    opacity: 1 !important;
    transform: none !important;
    border-top: var(--jamb-rule) solid var(--color-rule) !important;
    padding-top: 0.75rem !important;
  }
  .proj__layer .proj__tag,
  .proj__layer .proj__sub { opacity: 1 !important; }
  .proj__layer .proj__mark { stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
  .proj__index-item { color: var(--color-text-muted) !important; }
}
