/* ══════════════════════════════════════════════════════════════════
   photo-loupe.css — full-viewport single-photo viewer (Figma 26:890
   desktop / 46:257 mobile) + its caption toggle (45:166 / 46:287).

   Sandy's rule (2026-08-13): the component — image AND the nav row
   below it together — is 81vh. Rather than hardcode a second number
   for "just the image," the 81vh lands on .loupe-content and the
   image gets `flex:1 1 0; min-height:0`, so its actual height is
   whatever's left after the fixed-height control row and the gap
   between them — exactly Figma's own 640 = 680 (content) − 22 (gap) −
   18 (controls), reproduced by layout instead of a second constant
   that could drift from the first.

   Every kind (landscape/portrait/square) uses the SAME rule here —
   height fills the frame, width follows the image's own ratio — which
   is a genuine departure from css/photo-linear.css's per-kind system,
   not an oversight: Sandy said so explicitly ("all image ratio will be
   displayed with its height filling the frame, all have same height"),
   and it makes sense for a viewer where only one photo is ever on
   screen — there's no neighbouring photo for a kind-specific rule to
   stay proportionate AGAINST.
══════════════════════════════════════════════════════════════════ */

/* These three carry the `hidden` attribute as their closed/off state
   (js/photo-loupe.js), and every one of them also sets `display` below
   — which SILENTLY DEFEATS `hidden`. The UA stylesheet's
   `[hidden]{display:none}` is still a UA-origin rule, so any author
   rule setting display beats it regardless of specificity, and the
   attribute becomes decorative. Shipped exactly that way once: the
   loupe rendered permanently open, full-viewport, on top of every page
   including the root, which read as "the site is blank".

   So the closed state has to be re-asserted at author level. Kept as
   one grouped rule immediately above the rules it defends against,
   rather than three `[hidden]` variants scattered next to each — the
   point is that this is a property of the whole component, and any
   NEW element here that takes `hidden` needs adding to this list. */
.loupe[hidden],
.loupe-img[hidden],
.loupe-caption[hidden]{ display:none; }

/* The one place suppressing a focus outline is correct rather than an
   accessibility regression: .loupe is tabindex="-1", so it is never
   reachable by tabbing — it exists only as somewhere to PARK focus when
   the overlay opens (js/photo-loupe.js). Nothing navigates to it, so
   there is no "where am I" question for a ring to answer. Every control
   INSIDE it keeps its own .label:focus-visible ring untouched. */
.loupe:focus{ outline:none; }

.loupe{
  position:fixed; inset:0;
  z-index:10;
  background:var(--bg);
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  /* Same cap+centre as .stage (base.css) — a loupe opened on an
     ultrawide monitor shouldn't blow past the composition's own drawn
     size any more than the rest of the page does. Duplicated rather
     than shared because .loupe is a sibling of .stage, not a
     descendant (see index.html's comment on why). */
  max-width:1728px; margin-inline:auto;
  padding:0 max(24px, env(safe-area-inset-right, 0px)) 0 max(24px, env(safe-area-inset-left, 0px));
}

.loupe-content{
  width:100%;
  /* Figma's own content column is 1080 inside a 1280 frame — 100px
     margin each side, 7.8125% — reproduced as a fraction rather than a
     literal 1080 so it scales the same way every other measurement in
     this codebase does. */
  max-width:84.375%;
  height:81vh;
  display:flex; flex-direction:column;
  gap:22px;
}

.loupe-stage{
  flex:1 1 0; min-height:0;
  display:flex; align-items:center; justify-content:center;
  cursor:pointer;                   /* js/photo-loupe.js: click toggles the caption */
}

.loupe-img{
  height:100%; width:auto; max-width:100%;
  object-fit:contain;               /* never crop — this view's whole point is seeing the real image */
  display:block;
}

.loupe-caption{
  height:100%; width:100%;
  overflow-y:auto;                  /* safety net for an unusually long description; Figma's own text never needs it */
  display:flex; flex-direction:column; gap:22px;
}
.loupe-cap-title{ font-size:22px; letter-spacing:-0.22px; }
.loupe-cap-body{ display:flex; flex-direction:column; gap:22px; }
/* Matches js/photo-loupe.js's renderParagraphs — one blank line
   between paragraphs, same convention js/pages.js's textLines uses for
   log/description text, both ultimately authored in objkt token
   descriptions with the same blank-line-separated shape. */

.loupe-controls{
  flex:none;
  display:flex; align-items:center; justify-content:space-between;
  height:18px;
  font-size:18px; line-height:18px;
}

@media (max-width:719px){
  .loupe{ padding:0 24px; }
  .loupe-content{ max-width:100%; }
}
