/* Hover on the four project cards.

   In Framer this was a component variant, and variants are swapped by the
   React bundle at runtime. Removing that bundle (16dae86) took the hover
   with it — the exported markup only ever held the resting frame, which is
   why the cards went flat. The traces are still visible in index.html: the
   image wrapper carries `will-change: transform` and a bare
   `transform: perspective(1200px)`, a transform set up for an animation
   that no longer had anything driving it.

   Rebuilt here in plain CSS, so it survives without a runtime.

   Two things happen together:

     - the image scales up a little inside its own box
     - a one-line description unfolds under the title, and the text bar
       grows upward over the bottom of the image to make room

   Geometry worth knowing before touching the numbers: the card is 352px
   tall (362 tablet, 360 phone) in a 4/2/1 column grid, the image
   (.framer-1b1dgnl) is absolutely positioned at `inset: 0 0 64px`, and the
   text bar (.framer-k67zpx) is the only element in normal flow, packed to
   the bottom by the card's `justify-content: flex-end`. So the bar grows
   into the image rather than resizing it, and it can do that without a
   z-index because it is a positioned element later in the DOM — it paints
   over the image, and its background token is opaque. */

/* ---------- the image ---------- */

/* The wrapper is `overflow: visible` in Framer's CSS. The card clips at its
   own rounded rect anyway, but that lets the scaled image bleed down over
   the 64px the text bar sits in, where it would show for the frame or two
   before the bar's background covers it. Clipping at the image box is what
   makes the scale look like a zoom rather than a spill. */
.framer-LVB4V .framer-1b1dgnl {
  overflow: hidden;
}

.framer-LVB4V .framer-1b1dgnl img {
  transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.3, 1);
}

.framer-LVB4V.framer-gs4tzi:hover .framer-1b1dgnl img,
.framer-LVB4V.framer-gs4tzi:focus-visible .framer-1b1dgnl img {
  transform: scale(1.06);
}

/* A picture from the project itself — the top image of its page, or for
   Politiet the photo from the boat, since its top image is a phone with
   nothing behind it — laid over the logo and faded in, unhurried, on
   hover, so the card shows what the project looked like rather than only
   whose it was. It sits in the same wrapper
   as the logo and takes the same zoom from the rule above (and outranks
   that rule's transition, which would otherwise drop the fade). */
.framer-LVB4V .framer-1b1dgnl .work-card__hover {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  border-radius: inherit;
  opacity: 0;
  transition:
    opacity 0.7s ease,
    transform 0.5s cubic-bezier(0.2, 0.7, 0.3, 1);
}

.framer-LVB4V.framer-gs4tzi:hover .work-card__hover,
.framer-LVB4V.framer-gs4tzi:focus-visible .work-card__hover {
  opacity: 1;
}

/* ---------- the description ---------- */

/* Framer's rule puts a 2px gap on the bar, which never showed because the
   bar had a single child. With a second child it becomes 2px of dead space
   below the title while the description is collapsed, so the whole bar sits
   2px taller than it does today at rest. The spacing lives on the
   description instead, where it collapses along with it. */
.framer-LVB4V .framer-k67zpx {
  gap: 0;
}

/* 0fr -> 1fr rather than max-height: the row animates to the text's real
   height, so a description that wraps to three lines on a narrow card
   opens exactly as far as it needs to and no further. The inner element
   carries the overflow, because that is the box being squeezed. */
.framer-LVB4V .work-card__desc {
  display: grid;
  grid-template-rows: 0fr;
  width: 100%;
  opacity: 0;
  transition:
    grid-template-rows 0.38s cubic-bezier(0.2, 0.7, 0.3, 1),
    opacity 0.24s ease;
}

.framer-LVB4V .work-card__desc > * {
  overflow: hidden;
  min-height: 0;
  padding-top: 6px;
  transform: translateY(6px);
  transition: transform 0.38s cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* 14px, not the 16px of the preset it borrows its face from: the cards are
   about 264px wide at the desktop breakpoint, 216px inside the bar's
   padding, and 16px put these sentences on four lines — enough growth to
   swallow a third of the image. 14px holds them to two or three. */
.framer-LVB4V .work-card__desc p {
  font-size: 14px;
  line-height: 1.45;
}

.framer-LVB4V.framer-gs4tzi:hover .work-card__desc,
.framer-LVB4V.framer-gs4tzi:focus-visible .work-card__desc {
  grid-template-rows: 1fr;
  opacity: 1;
}

.framer-LVB4V.framer-gs4tzi:hover .work-card__desc > *,
.framer-LVB4V.framer-gs4tzi:focus-visible .work-card__desc > * {
  transform: none;
}

/* The card had no focus style at all, so a keyboard user tabbing through
   the grid got the hover state above and nothing else to say which card
   was actually selected. */
.framer-LVB4V.framer-gs4tzi:focus-visible {
  outline: 2px solid var(--token-43464fc0-8f12-4214-bfdd-fa0c6aa29267, rgb(20, 20, 21));
  outline-offset: 3px;
}

/* ---------- no hover to hang it on ---------- */

/* A phone never fires hover, so gating the description on it would hide the
   sentence from every touch visitor permanently. It just stays open there. */
@media (hover: none) {
  .framer-LVB4V .work-card__desc {
    grid-template-rows: 1fr;
    opacity: 1;
  }

  .framer-LVB4V .work-card__desc > * {
    transform: none;
  }

  /* Nothing to fade it in with, and kept out of the layout so a lazy image
     that can never be seen is never downloaded either. */
  .framer-LVB4V .framer-1b1dgnl .work-card__hover {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .framer-LVB4V .framer-1b1dgnl img,
  .framer-LVB4V .work-card__desc,
  .framer-LVB4V .work-card__desc > * {
    transition: none;
  }

  /* The zoom is the part that moves; the description still appears, it just
     appears rather than unfolds. */
  .framer-LVB4V.framer-gs4tzi:hover .framer-1b1dgnl img,
  .framer-LVB4V.framer-gs4tzi:focus-visible .framer-1b1dgnl img {
    transform: none;
  }
}
