/* ------------------------------------------------------------------
   JOVIK — portfolio "live windows" layer (v4)

   v3 was correct but too dark to read. The chrome bar (#191c23 ->
   #101319) sat only a few values above the card glass (#0b0c11) on a
   black page, and the dots were 17% white: on a screen at moderate
   brightness, or with a warm/night filter on, the whole window frame
   effectively disappeared. A capture with perfect gamma showed it
   fine, which is exactly why it went unnoticed for days.

   v4 keeps the geometry and every behaviour of v3 and only raises
   contrast, so the frame survives a real screen:

     · chrome bar lifted well clear of the glass
     · dots and hairline roughly doubled in strength
     · address-bar text and fill brightened
     · a faint outer edge so each card reads as a window on its own

   Served from /_next/static, which Caddy marks immutable — publish a
   new -vN filename rather than editing this one in place.
   ------------------------------------------------------------------ */

:root {
  --jvp-bar: 32px;
  --jvp-bar-sm: 26px;
  --jvp-glass: #0b0c11;
  --jvp-chrome-a: #262b36;
  --jvp-chrome-b: #171b23;
  --jvp-hair: rgba(255, 255, 255, 0.14);
  --jvp-dot: rgba(255, 255, 255, 0.34);
  --jvp-url: #9aa2b2;
  --jvp-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --jvp-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* ==================================================================
   1. The window shell
   ================================================================== */

#proyectos a.group,
.jvp-win,
.jv-shot {
  padding-top: var(--jvp-bar);
  background: var(--jvp-glass);
  position: relative;
  isolation: isolate;
  /* v4: a window needs an edge. Without this the card dissolves into
     the page on anything but a high-contrast panel. */
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.09), 0 18px 40px -24px rgba(0, 0, 0, 0.9);
}

#proyectos a.group::before,
.jvp-win::before,
.jv-shot::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--jvp-bar);
  z-index: 12;
  border-bottom: 1px solid var(--jvp-hair);
  background:
    radial-gradient(circle 3.5px at 14px 50%, var(--jvp-dot) 99%, transparent 100%),
    radial-gradient(circle 3.5px at 28px 50%, var(--jvp-dot) 99%, transparent 100%),
    radial-gradient(circle 3.5px at 42px 50%, var(--jvp-dot) 99%, transparent 100%),
    linear-gradient(180deg, var(--jvp-chrome-a), var(--jvp-chrome-b));
}

#proyectos a.group[data-host]::after,
.jvp-win[data-host]::after,
.jv-shot[data-host]::after {
  content: attr(data-host);
  position: absolute;
  top: 6px;
  left: 58px;
  right: 10px;
  z-index: 13;
  box-sizing: border-box;
  height: calc(var(--jvp-bar) - 12px);
  line-height: calc(var(--jvp-bar) - 14px);
  padding: 0 10px 0 20px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 999px;
  background:
    radial-gradient(circle 2.5px at 10px 50%, rgba(226, 230, 238, 0.85) 99%, transparent 100%),
    rgba(255, 255, 255, 0.075);
  color: var(--jvp-url);
  font-family: var(--jvp-mono);
  font-size: 10.5px;
  letter-spacing: 0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color 0.35s var(--jvp-ease), border-color 0.35s var(--jvp-ease),
    background-color 0.35s var(--jvp-ease);
}

#proyectos a.group:hover[data-host]::after,
.jvp-item:hover .jvp-win[data-host]::after {
  color: #e8eaee;
  border-color: rgba(255, 255, 255, 0.2);
  background-color: rgba(255, 255, 255, 0.08);
}

@media (max-width: 640px) {
  :root {
    --jvp-bar: var(--jvp-bar-sm);
  }
  #proyectos a.group[data-host]::after,
  .jvp-win[data-host]::after,
  .jv-shot[data-host]::after {
    left: 52px;
    font-size: 9.5px;
  }
}

/* ==================================================================
   2. Focus — hovering one window sends the rest back
   This is the change that makes the grid read as a gallery rather
   than a contact sheet. Scoped per grid container so hovering the
   section heading never dims anything.
   ================================================================== */

#proyectos a.group,
.jvp-item .jvp-win,
.jvp-item .jvp-meta {
  transition: opacity 0.45s var(--jvp-ease), transform 0.5s var(--jvp-ease),
    box-shadow 0.5s var(--jvp-ease), border-color 0.35s var(--jvp-ease);
}

/* Dim with opacity ONLY. `filter` here creates a compositing context on the
   card, and Chrome then rendered the transformed screenshot inside it as a
   blank rectangle — every image in the grid vanished on hover. */
@media (hover: hover) {
  #proyectos div.grid:hover a.group:not(:hover) {
    opacity: 0.35;
  }

  .jvp-wall:hover .jvp-item:not(:hover) .jvp-win,
  .jvp-wall:hover .jvp-item:not(:hover) .jvp-meta {
    opacity: 0.38;
  }
}

/* ==================================================================
   3. Movement
   ================================================================== */

@media (prefers-reduced-motion: no-preference) {
  /* Deliberately plain 2D transforms and no will-change. Both translate3d
     and will-change pin the screenshot to its own compositing layer, and a
     layer inside a card that later gets its own stacking context rendered
     blank in Chrome. A 2D transform is composited only while it animates. */
  #proyectos a.group img,
  .jvp-win img {
    transform: translateY(var(--jvp-y, 0px)) scale(var(--jvp-s, 1.12));
    transition: transform 0.5s var(--jvp-ease);
  }

  #proyectos a.group:hover img,
  .jvp-item:hover .jvp-win img {
    --jvp-s: 1.17;
  }

  #proyectos a.group:hover,
  .jvp-item:hover .jvp-win {
    transform: translateY(-8px);
    box-shadow: 0 40px 70px -34px rgba(0, 0, 0, 0.95);
  }

  /* light sweeping across the glass. The screenshot wrapper's own
     pseudo-element is free, so no node has to be added. */
  #proyectos a.group > div.overflow-hidden::after,
  .jvp-frame::after {
    content: "";
    position: absolute;
    top: -60%;
    bottom: -60%;
    left: -40%;
    right: -40%;
    z-index: 5;
    pointer-events: none;
    background: linear-gradient(
      104deg,
      transparent 42%,
      rgba(255, 255, 255, 0.14) 49%,
      transparent 57%
    );
    opacity: 0;
    transform: translateX(-55%);
  }

  #proyectos a.group:hover > div.overflow-hidden::after,
  .jvp-item:hover .jvp-frame::after {
    opacity: 1;
    transform: translateX(55%);
    transition: transform 1.15s var(--jvp-ease), opacity 0.35s var(--jvp-ease);
  }
}

/* pointer spotlight. On the homepage this rides the ring overlay that
   is already in the markup; on the wall it is a dedicated span. */
#proyectos a.group > span.pointer-events-none,
.jvp-glow {
  background: radial-gradient(
    340px circle at var(--jvp-mx, 50%) var(--jvp-my, 50%),
    rgba(210, 214, 221, 0.15),
    rgba(210, 214, 221, 0) 62%
  );
  opacity: 0;
  transition: opacity 0.4s var(--jvp-ease);
}

#proyectos a.group:hover > span.pointer-events-none,
.jvp-item:hover .jvp-glow {
  opacity: 1;
}

/* ==================================================================
   4. The portfolio wall (/proyectos/)
   ================================================================== */

.jvp-wall {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.75rem 1.5rem;
  margin: 2.5rem 0 1rem;
}

@media (min-width: 860px) {
  .jvp-wall {
    grid-template-columns: repeat(2, 1fr);
    gap: 2.75rem 1.75rem;
  }
  /* the lead and closing cases run full width, so the wall opens and
     closes on a big window instead of six equal thumbnails */
  .jvp-item.feat {
    grid-column: 1 / -1;
  }
  .jvp-item.feat .jvp-frame {
    aspect-ratio: 21 / 9;
  }
  .jvp-item.feat .jvp-meta h3 {
    font-size: 1.45rem;
  }
  .jvp-item.feat .jvp-meta p {
    max-width: 60ch;
  }
}

/* The wall sits inside .jv-prose, whose `a` rule underlines everything —
   outrank it rather than leaving the captions looking like body links. */
.jvp-item,
.jv-prose a.jvp-item,
.jv-prose a.jvp-item:hover {
  display: block;
  text-decoration: none;
  color: inherit;
}

.jvp-win {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--jv-line, rgba(255, 255, 255, 0.08));
  border-radius: 16px;
  box-shadow: 0 18px 44px -30px rgba(0, 0, 0, 0.9);
}

.jvp-item:hover .jvp-win {
  border-color: rgba(255, 255, 255, 0.18);
}

.jvp-frame {
  position: relative;
  overflow: hidden;
  aspect-ratio: 16 / 10;
  background: var(--jvp-glass);
}

.jvp-win img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
}

.jvp-glow {
  position: absolute;
  inset: 0;
  z-index: 14;
  pointer-events: none;
}

.jvp-meta {
  padding: 1.05rem 0.15rem 0;
}

.jvp-meta .k {
  display: block;
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--jv-faint, #6b7180);
  margin-bottom: 0.5rem;
}

.jvp-meta h3 {
  font-family: var(--font-display), var(--font-inter), sans-serif;
  font-size: 1.18rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 0 0 0.5rem;
  color: var(--jv-fg, #f6f7f9);
}

.jvp-meta p {
  margin: 0;
  font-size: 0.94rem;
  line-height: 1.62;
  color: var(--jv-muted, #8b93a3);
  max-width: 46ch;
}

.jvp-go {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin-top: 0.85rem;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--jv-fg-2, #d2d6dd);
}

.jvp-go svg {
  transition: transform 0.35s var(--jvp-ease);
}

.jvp-item:hover .jvp-go svg {
  transform: translateX(4px);
}

.jvp-item:focus-visible {
  outline: none;
}

.jvp-item:focus-visible .jvp-win {
  box-shadow: 0 0 0 2px var(--jv-bg, #050506), 0 0 0 4px rgba(210, 214, 221, 0.7);
}

/* staggered reveal, guarded by .jvp-js so the wall stays visible when
   the script does not run */
.jvp-js .jvp-item {
  opacity: 0;
  transform: translateY(26px) scale(0.99);
  transition: opacity 0.55s var(--jvp-ease), transform 0.55s var(--jvp-ease);
  transition-delay: var(--jvp-d, 0ms);
}

.jvp-js .jvp-item.is-in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .jvp-js .jvp-item {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ==================================================================
   5. Case-study shots keep the frame but stay still
   ================================================================== */

.jv-shot {
  overflow: hidden;
}

.jv-shot img {
  display: block;
}

@media print {
  #proyectos a.group::before,
  .jvp-win::before,
  .jv-shot::before,
  #proyectos a.group::after,
  .jvp-win::after,
  .jv-shot::after {
    display: none;
  }
}
