/* ==========================================================================
   Portfolio — every practice site we hold a capture of, named

   The collage on the Practice Websites page is the same list without names;
   this is the one that answers "which practices?". Deliberately plain: the
   captures are the content, so nothing here competes with them.
   ========================================================================== */

.mf-pf {
  position: relative;
  padding: 140px 40px 110px;
}

.mf-pf__inner {
  max-inline-size: var(--section-max);
  margin-inline: auto;
}

.mf-pf__head {
  text-align: center;
  max-inline-size: 760px;
  margin: 0 auto 56px;
}

.mf-pf__head .mf-eyebrow { margin-block-end: 20px; }

.mf-pf__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 40px;
}

.mf-pf__item {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* The card's own chrome. It comes from the shared shot-card partial, but its
   styling lives in the Practice Websites stylesheet, which this page does not
   load — so the frame is dressed here rather than borrowing from a page the
   reader may never visit.

   Every capture here is the whole homepage, top to footer, so a card is a
   window onto something several times its own height: it opens on the top of
   the site and travels down to the footer while you are on it. The window is
   a ratio rather than a height so it tracks the grid column, and each card
   carries its capture's own aspect ratio as --pf-ratio (set in portfolio.njk
   from the real pixel size) — that is what tells the pan how far it has to
   travel, and so how long it should take. */
.mf-pf__item .mf-pw-shot__link {
  display: block;
  text-decoration: none;
}

.mf-pf__item .mf-pw-shot__frame {
  display: block;
  border-radius: var(--radius-inset);
  overflow: hidden;
  background: var(--paper-200);
  border: 1px solid var(--border-light);
  box-shadow: var(--shadow-tile);
}

/* container-type: size is what makes 100cqh below mean "the height of this
   window" — the one number the travel distance needs and that no other unit
   can give, since the image's own height is the percentage basis. */
.mf-pf__item .mf-pw-shot__view {
  display: block;
  container-type: size;
  aspect-ratio: 4 / 3;
  overflow: hidden;
}

/* The capture is taller than the window by (its height − the window's), and
   translateY percentages resolve against the image's own height — so
   -100% + 100cqh lands the footer exactly on the bottom edge, whatever the
   page's length.

   Pace, not duration, is what stays constant. --pf-pace is how many window
   widths the page travels in a second, so a long site takes proportionally
   longer than a short one and every card drifts at the same speed rather
   than every card finishing at the same moment. The travel is
   (ratio − 0.75) widths, hence the division below.

   0.24 is aimed at the drift of the hero's browser window on the Practice
   Websites page, not matched to it: that one runs about 0.05 widths a second,
   which on the longest capture here would be over two minutes of hovering.
   This is the same unhurried register inside a length a pointer can actually
   sit through — a few seconds of hover buys most of a windowful of page,
   which is the point: a look inside, not a race to the footer. The return is
   quick and eased, so leaving a card feels like letting go rather than like
   a second animation. */
.mf-pf__item {
  --pf-ratio: 4;
  --pf-pace: 0.24;
}

.mf-pf__item .mf-pw-shot__view img {
  display: block;
  inline-size: 100%;
  block-size: auto;
  transform: translateY(0);
  transition: transform 620ms var(--ease-out, cubic-bezier(0.22, 1, 0.36, 1));
}

.mf-pf__item:hover .mf-pw-shot__view img,
.mf-pf__item:focus-within .mf-pw-shot__view img {
  transform: translateY(calc(-100% + 100cqh));
  transition-duration: calc((var(--pf-ratio) - 0.75) / var(--pf-pace) * 1s);
  /* Linear, and deliberately. An eased ramp is scaled by the duration, so on
     the longest capture — nearly half a minute of travel — the soft start ate
     the first several seconds and the card looked broken. At this pace the
     motion is gentle enough that it needs no easing to begin kindly. */
  transition-timing-function: linear;
}

/* No pointer means no hover to drive it, so on touch the reader's own scroll
   does: the timeline is declared on the frame rather than the image because a
   view() range measured on an 8000px-tall image would barely move. */
@media (hover: none) {
  .mf-pf__item .mf-pw-shot__frame {
    view-timeline: --pf-card block;
  }

  .mf-pf__item .mf-pw-shot__view img {
    transition: none;
    animation: mf-pf-pan linear both;
    animation-timeline: --pf-card;
    animation-range: entry 100% exit 0%;
  }
}

@keyframes mf-pf-pan {
  to { transform: translateY(calc(-100% + 100cqh)); }
}

/* Reduced motion keeps the window and the framing, and drops the travel:
   the card shows the top of the site and stays there. */
@media (prefers-reduced-motion: reduce) {
  .mf-pf__item .mf-pw-shot__view img,
  .mf-pf__item:hover .mf-pw-shot__view img,
  .mf-pf__item:focus-within .mf-pw-shot__view img {
    transform: none;
    transition: none;
    animation: none;
  }
}

/* The capture links out on its own; this is the same destination said in
   words, for anyone who wants to know whose site they are looking at. */
.mf-pf__name {
  font-family: var(--font-ui);
  font-size: 15px;
  font-weight: var(--weight-semibold);
  line-height: 1.4;
  color: var(--ink);
  text-decoration: none;
}

.mf-pf__name:hover { color: var(--color-primary, var(--flare-600)); }

.mf-pf__more {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  margin: 72px auto 0;
  text-align: center;
}

.mf-pf__more-title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: clamp(24px, 2.6vw, 34px);
  line-height: 1.2;
}

.mf-pf__more-body {
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.6;
  color: var(--ink-muted);
  max-inline-size: 46ch;
}

.mf-pf__back {
  margin: 44px auto 0;
  text-align: center;
}

@media (max-width: 780px) {
  .mf-pf { padding: 120px 22px 90px; }
  .mf-pf__grid { gap: 32px; }
}
