/* ==========================================================================
   lightbox.css — one picture, centred, everything else pushed back.

   Z-INDEX 56, AND THE TWO NUMBERS EITHER SIDE ARE THE WHOLE REASON. The
   gallery's page tint is 55 and the bottom bar is 60, so this sits in the one
   gap between them: the veil darkens the tinted page, the picture opens ABOVE
   the tint and so keeps its own colour, and the bar stays lit and untouched —
   which is what the mock-ups show and also what the bar is for. It is the
   site's one constant; a lightbox that dimmed it would make it a different
   object on this page than on every other.

   THE ROOT IS NEVER HIDDEN. It was — `visibility:hidden` until open — and that
   quietly threw away half the feature: closing removed the class, the whole
   overlay vanished on the same frame, and the flight home animated where
   nobody could see it. So the root stays present and transparent to the
   pointer, and the three parts inside it are shown and hidden on their own.
   ========================================================================== */

.lbox{
  position: fixed; inset: 0; z-index: 56;
  pointer-events: none;
}
.lbox.is-open{ pointer-events: auto; }

.lbox__veil{
  position: absolute; inset: 0;
  background: #000;
  opacity: 0;
  transition: opacity var(--lbox-ms, 420ms) ease;
}
.lbox.is-open .lbox__veil{ opacity: var(--lbox-veil, .6); }

/* VISIBLE WHILE OPEN *AND* WHILE FLYING HOME. `is-flying` is held by the
   module for exactly the length of the return, which is the only way the way
   out gets to be as animated as the way in. */
.lbox__box{
  position: absolute; top: 0; left: 0;
  transform-origin: 0 0;
  will-change: transform;
  visibility: hidden;
}
.lbox.is-open .lbox__box,
.lbox.is-flying .lbox__box{ visibility: visible; }

.lbox__img{
  display: block; width: 100%; height: 100%;
  object-fit: contain;
  /* CONTAIN, NOT COVER. The grid crops its plates to a fixed frame because
     thirty of them have to tile; opened on its own, the point is to see the
     whole photograph, so nothing is cut. */
}

/* ---- THE PICTURE'S OWN GRAIN ------------------------------------------------
   THE PAGE'S GRAIN IS NOT THE SAME ON BOTH PAGES, AND THAT IS THE BUG THIS
   FIXES. .grain is one fixed layer at z-index 999, so it does fall over an
   opened picture everywhere — but css/work-grid.css deliberately retunes it for
   the work page, whose field is nearly black:

     gallery (css/ui.css)     overlay · opacity .13 · contrast 300% · 5em
     work    (work-grid.css)  lighten · opacity .06 · contrast  50% · 1em

   Those numbers are right for that FIELD — the note in that file explains why
   overlay does nothing against black — and they are why the same photograph
   opened on the two pages arrives with grain on one and almost none on the
   other. The field's setting is not the picture's setting.

   So the picture carries its own, at the gallery's values, on both pages. Same
   tile, same stepped animation, same blend; it lives inside the flying box, so
   it scales and travels with the photograph instead of sitting still over it.
   The one thing it must NOT do is take the pointer — a click anywhere on the
   picture closes it. */
.lbox__grain{
  position: absolute; inset: 0;
  pointer-events: none;
  opacity: 0;
  background: url('../assets/grain/noise.png') 50% 50% /
              var(--lbox-grain-size, 5em) repeat;
  filter: contrast(var(--lbox-grain-contrast, 300%))
          brightness(var(--lbox-grain-brightness, 80%));
  mix-blend-mode: var(--lbox-grain-blend, overlay);
  transition: opacity 160ms ease;
}
.lbox.is-open .lbox__grain,
.lbox.is-flying .lbox__grain{ opacity: var(--lbox-grain, .13); }

/* Stepped, not eased, for the reason css/ui.css gives about the page's own:
   the texture has to JUMP between positions or it reads as a pattern sliding
   across the picture rather than as grain being resampled. */
.lbox__grain[data-grain-animate="true"]{
  animation: grain var(--lbox-grain-speed, .85s) steps(1, end) infinite;
}

/* The same four corner marks the grid puts on its cells, so an opened picture
   is recognisably the same object as the card it came from. The delay is on
   the OPEN rule only — on the way out they should leave with everything else
   rather than linger for the length of the flight. */
.lbox__tick{
  position: absolute; width: 5px; height: 5px;
  background: currentColor;
  opacity: 0;
  transition: opacity 140ms ease;
}
.lbox.is-open .lbox__tick{
  opacity: 1;
  transition: opacity 160ms ease var(--lbox-ms, 420ms);
}
.lbox__tick--tl{ left: calc(var(--lbox-out) * -1px); top: calc(var(--lbox-out) * -1px); }
.lbox__tick--tr{ right: calc(var(--lbox-out) * -1px); top: calc(var(--lbox-out) * -1px); }
.lbox__tick--bl{ left: calc(var(--lbox-out) * -1px); bottom: calc(var(--lbox-out) * -1px); }
.lbox__tick--br{ right: calc(var(--lbox-out) * -1px); bottom: calc(var(--lbox-out) * -1px); }

/* FOLLOWS THE POINTER, DOES NOT REPLACE IT. The mock-up keeps the ordinary
   arrow and puts the words beside it, which is the honest version — a hidden
   system cursor with a div pretending to be one always lags by a frame.

   Two states, one element: `is-hot` is hovering a picture with nothing open
   (CLICK TO OPEN), `is-open` is a picture up (CLICK TO CLOSE). */
.lbox__label{
  position: fixed; left: 0; top: 0;
  transform: translate3d(-9999px, -9999px, 0);

  /* THE SITE'S OWN SMALL-LABEL SETTING, not a monospace of its own. This was
     PP Supply Mono at 10px with +.12em of tracking, which is three separate
     disagreements with everything around it: the site sets its labels in the
     main face, and — the one that actually shows — its tracking is NEGATIVE.
     --ui-track is -0.04em. Letters spaced apart where every other label on the
     page is tucked together reads as a different typeface even when it is not.
     `inherit` rather than a named family, so it follows whatever the page is
     set in and cannot drift again. */
  font-family: inherit;
  font-size: var(--ui-10, 10px);
  font-weight: 400;
  letter-spacing: var(--ui-track, -0.04em);
  line-height: 1;
  text-transform: uppercase;

  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 160ms ease;
}
.lbox.is-hot  .lbox__label,
.lbox.is-open .lbox__label{ opacity: 1; }

.lbox--light{ color: #fff; }
.lbox--dark { color: #000; }

/* ==========================================================================
   LETTING THE CLICK THROUGH, and only the click.

   .wgrid__world is pointer-events:none — deliberately, so the whole field
   reads as one draggable surface and no individual card can start a native
   image drag. That also means a pointer event never has a cell as its target.

   The fix is the standard parent-none/child-auto pair: the world stays
   transparent to the pointer, the cells become targets again. Dragging is
   unaffected — the event still bubbles from the cell up to the root, which is
   where js/work-grid.js listens. The <img> inside stays pointer-events:none,
   so picking a card up still cannot start a browser file-drag.

   NOTE this is not on its own enough on the work page: that root also takes
   POINTER CAPTURE on pointerdown, which retargets every later event to itself.
   See the note beside `downCell` in js/lightbox.js.
   ========================================================================== */
body[data-page="design"]  .wgrid__cell{ pointer-events: auto; }
body[data-page="gallery"] .pathg__it { pointer-events: auto; }
