/* ───────────────────────────────────────────────────────────────────────────
   Holographic shimmer + 3D tilt for the marketing screenshots.
   100% ORIGINAL / clean-room — no third-party (GPL) code or assets.

   ALL of the look is driven by tunable knobs (the --holo-... custom properties
   below). The holo lab (docs/current-work/holo-lab/our-lab.html) overrides these
   live via sliders so the values can be dialled in by hand; whatever values look
   right there get pasted back into the :root blocks here.
   ─────────────────────────────────────────────────────────────────────────── */

:root{
  /* ── Tunable knobs — LIGHT theme (default) — dialled in via the holo lab ── */
  --holo-shine:.35;        /* rainbow strength            (0–1)   */
  --holo-glare:.30;        /* glare / reflection strength (0–1)   */
  --holo-alpha:.24;        /* rainbow colour alpha        (0–.8)  */
  --holo-angle:105deg;     /* rainbow direction           (deg)   */
  --holo-size:160%;        /* rainbow band scale          (%)     */
  --holo-glare-alpha:.60;  /* glare brightness            (0–1)   */
  --holo-glare-size:50%;   /* glare spread                (%)     */
  --holo-tilt:.80;         /* 3D tilt amount              (0–2)   */
  --holo-scale:1.05;       /* hover pop scale             (1–1.3) */
  --holo-grain:.45;        /* film grain, light theme     (0–1)   */
  --holo-return:.20;       /* snap-back speed on un-hover (.05 slow – .4 fast) */
}
:root[data-theme="dark"]{
  /* ── Tunable knobs — DARK theme — dialled in via the holo lab ── */
  --holo-shine:.15;
  --holo-glare:.11;
  --holo-alpha:.25;
  --holo-angle:125deg;     /* warmer slant than light                */
  --holo-size:100%;        /* tighter rainbow bands than light       */
  --holo-glare-alpha:.50;
  --holo-tilt:.80;
  --holo-scale:1.05;
}

.card{
  --w:200px; --card-aspect:0.49;
  --card-opacity:0; --card-scale:1;
  --rotate-x:0deg; --rotate-y:0deg;
  --background-x:50%; --background-y:50%;
  --pointer-x:50%; --pointer-y:50%; --pointer-from-center:0;
  position:relative; display:inline-block; vertical-align:top;
  width:var(--w); aspect-ratio:var(--card-aspect); height:var(--card-h,auto);
  border-radius:1rem; z-index:0;
}
.card.interacting{ z-index:3; }

.card__translater{
  display:block; width:100%; height:100%; border-radius:inherit;
  transition:transform .16s ease;
}
.card__rotator{
  display:block; width:100%; height:100%; border-radius:inherit;
  pointer-events:auto; transition:box-shadow .4s ease;
}
/* CRISPNESS: only promote to a GPU layer + apply the 3D tilt WHILE interacting.
   A permanent translate3d / will-change / rotateY(0deg) keeps every card on a
   compositor layer that rasterises below device-pixel-ratio on hi-DPI screens —
   that blurred the screenshots + text at rest. At rest the card now renders in
   the normal page raster, so it's pin-sharp; the layer only exists during hover. */
.card.interacting .card__translater{ perspective:720px; transform:scale(var(--card-scale,1)); will-change:transform; }
.card.interacting .card__rotator{
  transform:rotateY(var(--rotate-x)) rotateX(var(--rotate-y));
  box-shadow:0 20px 44px -18px rgba(0,0,0,.55);
}

/* isolation:isolate is critical — it forces the shine/glare blend modes to mix
   with the phone IMAGE only, not the page/other cards behind. Without it the
   overlapping hero cards blend against different backdrops left vs right, which
   showed up as a hard vertical split (one half shiny, one half dark). */
/* display:block is required — .card__front is a <span> (inline by default), and an
   inline positioned element gives its absolute children (shine/glare) a broken
   containing block: inset:0 covered only HALF the card (the hard vertical seam).
   Inline also ignores overflow:hidden, so the rounded-corner clip never applied. */
.card__front{ position:relative; display:block; width:100%; height:100%; border-radius:inherit; overflow:hidden; }
/* isolation only matters while the blend layers are mounted; keeping it off at rest
   means the front isn't a render surface, so the screenshot uses the browser's
   high-quality CPU downscaler (crisp) instead of a composited bilinear one. */
.card.fx .card__front{ isolation:isolate; }
.card__rotator img{
  display:block; width:100%; height:100%; object-fit:cover; border-radius:inherit;
  pointer-events:auto;
  /* The card now owns the whole presentation. The screenshot's own border /
     shadow / :hover transform (from .hero-trio img, [data-shot]) fought the card:
     the cream border vanished on light themes, the box-shadow doubled, and the
     :hover translateY shoved the image up inside the clipped frame (logo jammed to
     the top + a hard shadow band below). Neutralise them; the card draws the edge
     and the lift shadow instead. */
  border:1px solid rgba(0,0,0,.16) !important;
  box-shadow:none !important; transform:none !important; transition:none !important;
  cursor: zoom-in;  /* small, consistent system magnifier (the 48px custom SVG was rejected in top frames and only showed huge inside iframes) */
}
:root[data-theme="dark"] .card__rotator img{ border-color:rgba(255,255,255,.14) !important; }

.card__shine, .card__glare{ position:absolute; inset:0; border-radius:inherit; pointer-events:none; display:none; }
/* CRISPNESS pt.2: mix-blend-mode forces the whole card onto a GPU layer (even at
   opacity 0), which downscales the screenshot at low quality on hi-DPI screens ->
   blurry text AT REST. So the blend layers only exist while the effect is showing:
   JS adds .fx whenever --card-opacity > 0 (hover + the gradual fade-out), and drops
   it once faded. At true rest there's no blend layer, so the screenshot is crisp. */
.card.fx .card__shine, .card.fx .card__glare{ display:block; }

/* Rainbow iridescence. `screen` (dark) / `multiply` (light) show it EVENLY over
   dark or bright pixels — color-dodge only lit bright areas (the old "half" bug). */
.card__shine{
  opacity:calc(var(--card-opacity) * var(--holo-shine));
  background-image:repeating-linear-gradient(var(--holo-angle),
    hsla(0,85%,72%,var(--holo-alpha))   0%,  hsla(48,85%,72%,var(--holo-alpha))  9%,
    hsla(140,75%,68%,var(--holo-alpha)) 18%, hsla(200,85%,72%,var(--holo-alpha)) 27%,
    hsla(280,80%,76%,var(--holo-alpha)) 36%, hsla(330,85%,74%,var(--holo-alpha)) 45%,
    hsla(0,85%,72%,var(--holo-alpha))  54%);
  background-size:var(--holo-size) var(--holo-size);
  background-position:var(--background-x) var(--background-y);
  mix-blend-mode:screen;
}
:root:not([data-theme="dark"]) .card__shine{ mix-blend-mode:multiply; }

/* light-theme only: subtle film grain (our own SVG noise) — also gated to .fx so it
   doesn't keep the card composited (and blurry) at rest. */
:root:not([data-theme="dark"]) .card.fx .card__front::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  opacity:calc(var(--card-opacity) * var(--holo-grain));
  background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjAiIGhlaWdodD0iMTYwIj48ZmlsdGVyIGlkPSJnIj48ZmVUdXJidWxlbmNlIHR5cGU9ImZyYWN0YWxOb2lzZSIgYmFzZUZyZXF1ZW5jeT0iMC44NSIgbnVtT2N0YXZlcz0iMiIgc3RpdGNoVGlsZXM9InN0aXRjaCIvPjxmZUNvbG9yTWF0cml4IHR5cGU9InNhdHVyYXRlIiB2YWx1ZXM9IjAiLz48L2ZpbHRlcj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWx0ZXI9InVybCgjZykiLz48L3N2Zz4=");
  background-size:160px 160px; mix-blend-mode:soft-light;
}

/* Glare / reflection — a soft highlight that follows the pointer. */
.card__glare{
  opacity:calc(var(--card-opacity) * var(--holo-glare));
  background:radial-gradient(circle at var(--pointer-x) var(--pointer-y),
    rgba(255,255,255,var(--holo-glare-alpha)) 0%,
    rgba(255,255,255,calc(var(--holo-glare-alpha) * .35)) 18%,
    rgba(255,255,255,0) var(--holo-glare-size));
  mix-blend-mode:screen;
}
:root:not([data-theme="dark"]) .card__glare{ mix-blend-mode:overlay; }

/* "Open in gallery" chip — TOUCH ONLY (desktop uses the magnifier cursor) */
.holo-open{
  position:absolute; top:50%; left:50%;
  width:46px; height:46px; border-radius:999px;
  display:none; align-items:center; justify-content:center;
  color:#fff; background:rgba(11,18,32,.55);
  border:1px solid rgba(255,255,255,.42);
  box-shadow:0 6px 18px rgba(0,0,0,.4);
  -webkit-backdrop-filter:blur(5px); backdrop-filter:blur(5px);
  transform:translate(-50%,-50%) translateZ(60px);
  pointer-events:none; z-index:30;
}
@media (hover:none), (pointer:coarse){ .holo-open{ display:flex; opacity:.92; } }

@media (prefers-reduced-motion:reduce){ .card *{ transition:none !important } }
