/* ============================================================
   Mosaic tile — the panel, its image and its caption. Ported from the mockup's
   `.proof__tile` / `.proof__meta` (styles/lithography.css).

   The GRID and the folds live in mosaic/style.css, and the SPAN comes from
   core's child layout — nothing about how many cells a tile covers is in here.
   One sheet per component, so a tile can never load without them.
   ============================================================ */
.vt-mosaic__tile {
  position: relative;
  margin: 0;
  /* min-height 0 / min-width 0: a grid item's automatic minimum size is its
     CONTENT's size, so a portrait SEM capture in a one-row tile would push the
     row taller than grid-auto-rows and silently break the mosaic's alignment.
     This is what lets object-fit crop instead of the track growing. */
  min-width: 0;
  min-height: 0;
}

.vt-mosaic__figure {
  position: relative;
  display: block;
  margin: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: var(--radius-lg);
  /* The mockup states #1a1228 — a lifted ink, so a tile reads as a panel before
     its image has arrived. Mixed here from the palette rather than hard-coded,
     and it is what a transparent PNG would sit on. */
  background: color-mix(in srgb, var(--color-ink) 88%, var(--color-dark-purple));
  border: 1px solid color-mix(in srgb, #ffffff 8%, transparent);
}

/* One rule for both media elements. A film tile is a picture tile that moves:
   same crop, same box, same panel behind it — which is why the mockup's own
   sheet also says `.appmosaic__fig img, .appmosaic__fig video` in one selector
   (styles/applications.css) rather than styling the clip apart. */
.vt-mosaic__img,
.vt-mosaic__video {
  display: block;
  width: 100%;
  height: 100%;
  /* The tile's shape is the GRID's, not the image's, which is the whole idea of
     a mosaic: every tile lines up on shared tracks and the picture is cropped
     to fit. An editor who wants the whole frame gives the tile more cells. */
  object-fit: cover;
}

/* The poster is the film's own still and object-fit crops it the same way, but
   a <video> with neither a poster nor a decoded frame paints TRANSPARENT, not
   black — so the tile's panel ground shows through and the hole reads as a
   panel waiting for its picture rather than as a fault. Stated here so that is
   true even if the figure's background ever changes. */
.vt-mosaic__video {
  background: transparent;
}

/* ---- the zoom button ----
   A button that IS the image: no padding, no chrome of its own, so the tile
   looks identical whether zooming is on or off. `display: block` and the 100%
   box are what keep the image filling the tile through the extra element. */
.vt-mosaic__zoom {
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  /* zoom-in is the mockup's own cursor on these tiles, and it is the only hint
     a pointer user needs that the tile opens. */
  cursor: zoom-in;
  /* the button is a box around an image; it must not add a text line box */
  font: inherit;
  color: inherit;
  -webkit-appearance: none;
  appearance: none;
}
.vt-mosaic__zoom:focus-visible {
  /* inset, because an outline outside the button is clipped by the figure's
     overflow: hidden and would simply not be visible */
  outline: none;
  box-shadow: inset 0 0 0 3px var(--color-light-purple);
}

/* ---- the caption ----
   Over the image, on the mockup's bottom-up scrim. The scrim is what makes 11px
   uppercase legible on an arbitrary photograph, so it is not decoration and it
   is not optional. */
.vt-mosaic__meta {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 14px 16px;
  background: linear-gradient(0deg, color-mix(in srgb, var(--color-ink) 85%, transparent), transparent);
  /* the caption must never eat the zoom button's clicks under it */
  pointer-events: none;
}
.vt-mosaic__label {
  font-family: var(--font-body);
  font-size: max(11px, var(--fs-floor, 0px));
  font-weight: var(--fw-bold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: var(--lh-snug);
  /* 78% white, where the mockup states 70%. Not a measured AA fix — it CANNOT be
     one: this label sits over an arbitrary photograph through a partial scrim, so
     there is no single ratio to quote, and the scrim is what actually carries the
     legibility. 78% is the value `--vt-fg-subtle` uses for subtle foreground on
     every dark surface on this site, so the caption matches the offices row and
     the eyebrow instead of being its own number.

     Stated literally rather than read from --vt-fg-subtle on purpose: the
     caption is on a dark scrim whatever the SECTION is, so on a light band the
     token would resolve to dark grey and the label would vanish. */
  color: color-mix(in srgb, #ffffff 78%, transparent);
}
.vt-mosaic__value {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--fw-medium);
  font-size: 18px;
  line-height: 1;
  color: #ffffff;
}

/* A tile two rows tall gets the mockup's bigger figure — it has the room, and
   the biggest tile in a mosaic is the one the section is really about. It cannot
   be keyed off core's child-layout class, which is hashed per value and so has
   no stable name; render.php mirrors the row span onto `data-vt-rows` for
   exactly this. */
.vt-mosaic__tile[data-vt-rows="2"] .vt-mosaic__value,
.vt-mosaic__tile[data-vt-rows="3"] .vt-mosaic__value { font-size: 28px; }

/* ---- the zoom dialog (built by view.js, styled here) ----
   One dialog per page, appended to <body>, so it escapes every ancestor's
   overflow, transform and stacking context — a lightbox inside a section with
   `overflow: hidden` is a lightbox clipped to that section. */
.vt-mosaic-dialog {
  width: min(96vw, 1400px);
  max-width: none;
  max-height: 94svh;
  padding: 0;
  border: 0;
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--color-ink) 92%, transparent);
  color: #ffffff;
  overflow: hidden;
}
.vt-mosaic-dialog::backdrop {
  background: color-mix(in srgb, var(--color-ink) 88%, transparent);
}
.vt-mosaic-dialog__img {
  display: block;
  width: 100%;
  max-height: 94svh;
  /* contain, not cover: the point of opening the tile is to see the WHOLE frame
     the mosaic cropped. */
  object-fit: contain;
  background: var(--color-ink);
}
.vt-mosaic-dialog__bar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 16px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--color-ink) 80%, transparent), transparent);
}
.vt-mosaic-dialog__cap {
  margin: 0;
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.45;
  color: color-mix(in srgb, #ffffff 88%, transparent);
  text-wrap: pretty;
}
.vt-mosaic-dialog__close {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 1px solid color-mix(in srgb, #ffffff 28%, transparent);
  border-radius: 50%;
  background: color-mix(in srgb, var(--color-ink) 60%, transparent);
  color: #ffffff;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}
.vt-mosaic-dialog__close:hover {
  border-color: color-mix(in srgb, #ffffff 56%, transparent);
}
.vt-mosaic-dialog__close:focus-visible {
  outline: 2px solid var(--color-light-purple);
  outline-offset: 2px;
}

/* ---- the pointer loupe ----
   Pointer-only, by construction: it is positioned from pointermove and it is
   never the only way to see the detail — the dialog above is. Hidden under
   reduced motion, as the mockup has it, because it is a thing that chases the
   cursor. */
.vt-mosaic-loupe {
  position: fixed;
  z-index: 9999;
  width: 260px;
  height: 260px;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -50%);
  transition: opacity 0.18s var(--ease-standard, ease);
  background-repeat: no-repeat;
  border: 1.5px solid color-mix(in srgb, #ffffff 38%, transparent);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--color-light-purple) 28%, transparent),
    0 8px 36px color-mix(in srgb, var(--color-ink) 70%, transparent),
    inset 0 0 0 1px color-mix(in srgb, #ffffff 6%, transparent);
  will-change: left, top;
}
.vt-mosaic-loupe.is-active { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .vt-mosaic-loupe { display: none; }
}
/* No loupe where there is no pointer to drive it. `hover: none` is the honest
   test — a touch screen reports it — and it is why the dialog exists. */
@media (hover: none) {
  .vt-mosaic-loupe { display: none; }
}
