/* =========================================================
   PROJECTS-ENTRANCE.CSS
   The scroll entrance for the project gallery on the projects
   page. Each card runs once, as it reaches the reader.

   ANIMATION ONLY -- opacity, transform and clip-path, none of
   which affect the box an element occupies. No layout, size,
   spacing, typography, colour, image or content is changed, and
   the hero entrance and the page transition are not touched.

   ---------------------------------------------------------
   THE HOVER RULE
   These cards already carry finished hover work in
   interactions.css. Nothing here declares a transition on an
   element that has one, and nothing here adds a shadow, dims a
   neighbouring card, or puts a brand rule on a card:

     .pj-card            has `transition: box-shadow` for the
                         hover's bloom -- NOT touched at all.
                         The card itself does not move or fade;
                         only what is inside it does.
     .pj-card__image     has `transition: transform` (the 1.028
                         zoom) -- NOT touched. The entrance's own
                         scale rides on .pj-card__frame, a
                         wrapper added inside the photo's frame
                         so the two transforms compose instead of
                         overwriting each other.
     .pj-card__row::before  is the hover's divider -- NOT
                         touched, and no new line is added.

   SAFETY: nothing is hidden until js/projects-entrance.js adds
   .is-armed to the grid. If that script is missing or fails, no
   rule here matches and every card is simply there from the
   first paint. Transitions live on the revealing rule, never on
   the arming one.
   ========================================================= */

:root {
  /* The same two curves as every other entrance on the site,
     restated so the files stay independent of load order. */
  --pjx-ease: cubic-bezier(0.40, 0, 0.20, 1);
  --pjx-ease-media: cubic-bezier(0.45, 0, 0.15, 1);

  --pjx-media: 850ms;   /* the photograph opening */
  --pjx-name: 580ms;
  --pjx-info: 560ms;
  --pjx-at-name: 180ms; /* the name, once the picture is moving */
  --pjx-at-info: 300ms; /* the information under it */
  --pjx-col: 120ms;     /* between the columns of one row */
}

/* ---------------------------------------------------------
   READING ORDER
   The grid fills in DOM order, and this page is RTL, so the
   first card of each row sits on the physical RIGHT. Staggering
   by COLUMN rather than by arrival keeps the wave running
   right-to-left across every row at exactly the same pace,
   whatever the browser happens to batch together.
   --------------------------------------------------------- */
.pj-grid.is-armed .pj-card:nth-child(3n + 1) { --pjx-step: 0ms; }
.pj-grid.is-armed .pj-card:nth-child(3n + 2) { --pjx-step: var(--pjx-col); }
.pj-grid.is-armed .pj-card:nth-child(3n + 3) { --pjx-step: calc(var(--pjx-col) * 2); }

/* The grid drops to two columns here (projects-page.css), so
   the wave has to count in twos as well. */
@media (max-width: 880px) {
  .pj-grid.is-armed .pj-card:nth-child(2n + 1) { --pjx-step: 0ms; }
  .pj-grid.is-armed .pj-card:nth-child(2n + 2) { --pjx-step: var(--pjx-col); }
}

/* ---------------------------------------------------------
   ARMED — set by the script, no transitions here
   --------------------------------------------------------- */

/* The picture opens upward. inset() is PHYSICAL
   (top right bottom left): a top inset of 100% leaves a
   zero-height sliver along the frame's bottom edge, and
   shrinking it to 0 opens the picture from there. The frame
   never moves -- clip-path has no effect on layout -- and
   .pj-card__media already has overflow:hidden, which is what
   clips the 2.5% while it settles. */
.pj-grid.is-armed .pj-card__media {
  clip-path: inset(100% 0 0 0);
}

.pj-grid.is-armed .pj-card__frame {
  transform: scale(1.025);
}

.pj-grid.is-armed .pj-card__name {
  opacity: 0;
  transform: translateY(8px);
}

/* Place, envelope and products are ONE group on ONE delay:
   they arrive together as the card's information, never a line
   at a time. */
.pj-grid.is-armed .pj-card__place,
.pj-grid.is-armed .pj-card__meta {
  opacity: 0;
}

/* ---------------------------------------------------------
   THE WRAPPER
   .pj-card__frame exists for one reason: to keep the entrance's
   scale off .pj-card__image, which already owns the hover's
   scale(1.028). Two transforms on one element overwrite each
   other; on two nested elements they compose. It fills the
   frame exactly, so the image's own width/height:100% still
   resolve against a definite box and nothing about the
   rendering changes.
   --------------------------------------------------------- */
.pj-card__frame {
  display: block;
  width: 100%;
  height: 100%;
}

/* ---------------------------------------------------------
   REVEALED
   --------------------------------------------------------- */

.pj-grid.is-armed .pj-card.is-in .pj-card__media {
  clip-path: inset(0 0 0 0);
  transition: clip-path var(--pjx-media) var(--pjx-ease-media) var(--pjx-step, 0ms);
}

.pj-grid.is-armed .pj-card.is-in .pj-card__frame {
  transform: scale(1);
  transition: transform var(--pjx-media) var(--pjx-ease-media) var(--pjx-step, 0ms);
}

.pj-grid.is-armed .pj-card.is-in .pj-card__name {
  opacity: 1;
  transform: translateY(0);
  transition:
    opacity var(--pjx-name) var(--pjx-ease) calc(var(--pjx-step, 0ms) + var(--pjx-at-name)),
    transform var(--pjx-name) var(--pjx-ease) calc(var(--pjx-step, 0ms) + var(--pjx-at-name));
}

.pj-grid.is-armed .pj-card.is-in .pj-card__place,
.pj-grid.is-armed .pj-card.is-in .pj-card__meta {
  opacity: 1;
  transition: opacity var(--pjx-info) var(--pjx-ease)
              calc(var(--pjx-step, 0ms) + var(--pjx-at-info));
}

/* ---------------------------------------------------------
   REDUCED MOTION — everything present, nothing moves
   --------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .pj-grid.is-armed .pj-card__media {
    clip-path: none;
    transition: none;
  }

  .pj-grid.is-armed .pj-card__frame,
  .pj-grid.is-armed .pj-card__name {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .pj-grid.is-armed .pj-card__place,
  .pj-grid.is-armed .pj-card__meta {
    opacity: 1;
    transition: none;
  }
}
