@layer components {
  /* ── Photo Review Lightbox ── */
  .photo-review {
    position: fixed;
    inset: 0;
    z-index: 100;
    background: #1a1d1a;
    display: flex;
    flex-direction: column;
    color: #fff;
    font-family: var(--font-ui);
  }

  /* ── Top bar ── */
  .photo-review__topbar {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 12px 20px;
    background: rgba(0, 0, 0, 0.4);
    flex-shrink: 0;
  }

  .photo-review__exit-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: var(--r-sm);
    color: var(--ink-400);
    transition: color 0.15s, background 0.15s;
  }

  .photo-review__exit-btn:hover {
    color: #fff;
    background: rgba(255, 255, 255, 0.1);
  }

  .photo-review__exit-btn svg {
    width: 16px;
    height: 16px;
  }

  .photo-review__category {
    font-size: 14px;
    font-weight: 500;
    color: var(--ink-200);
    flex: 1;
  }

  .photo-review__progress {
    font-size: 13px;
    color: var(--ink-400);
    font-variant-numeric: tabular-nums;
  }

  /* ── Stage (main photo area) ── */
  .photo-review__stage {
    flex: 1;
    /* min-height: 0 lets this flex item shrink below its content so its
       overflow:hidden and the image's max-height:100% actually bound the photo
       to the leftover space. Without it the image overflows behind the bottom
       bars (verdict + note on the checker) and gets clipped. */
    min-height: 0;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    padding: 16px;
  }

  /* Cursor affordance set by the image-zoom controller: grab when zoomed in,
     grabbing while panning. */
  .photo-review__stage.is-zoomed .photo-review__image { cursor: grab; }
  .photo-review__stage.is-grabbing .photo-review__image { cursor: grabbing; }

  .photo-review__image-wrap {
    /* Fill the stage with a definite height so the image's max-height: 100%
       resolves against it (a percentage height against an indefinite parent is
       ignored, which let tall images overflow and clip). */
    width: 100%;
    height: 100%;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .photo-review__image {
    max-width: 100%;
    /* Bound to the stage (which flexbox sizes to the space left by the top and
       bottom bars), not a fixed viewport guess, so the whole photo stays visible
       no matter how tall the bottom chrome is. */
    max-height: 100%;
    object-fit: contain;
    border-radius: var(--r-sm);
    /* The image-zoom controller drives `transform` (scale + translate); keep its
       origin centred so the pan clamp stays symmetric. Only opacity transitions,
       so dragging stays instant. */
    transform-origin: center center;
    transition: opacity 0.1s ease;
  }

  /* Subtle zoom controls, bottom-right of the stage. Muted until hover so they
     stay unobtrusive over the photo. */
  .photo-review__zoom-controls {
    position: absolute;
    right: 16px;
    bottom: 16px;
    display: flex;
    gap: 6px;
    z-index: 1;
  }

  .photo-review__zoom-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    color: var(--ink-200);
    background: rgba(0, 0, 0, 0.35);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: var(--r-md);
    cursor: pointer;
    opacity: 0.55;
    transition: opacity var(--transition), background var(--transition), border-color var(--transition);
  }

  .photo-review__zoom-controls:hover .photo-review__zoom-btn,
  .photo-review__zoom-btn:hover,
  .photo-review__zoom-btn:focus-visible {
    opacity: 1;
  }

  .photo-review__zoom-btn:hover {
    background: rgba(0, 0, 0, 0.55);
    border-color: rgba(255, 255, 255, 0.3);
  }

  .photo-review__zoom-btn svg {
    width: 16px;
    height: 16px;
  }

  .photo-review__placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 400px;
    height: 300px;
  }

  .photo-review__placeholder svg {
    width: 64px;
    height: 64px;
  }

  /* ── Bottom bar ── */
  /* Two rows: a compact control row (id, selection, downloads, hints) and a
     full-width caption row beneath it (see .photo-review__caption `order`). The
     caption row grows the bar into the letterbox band a landscape photo would
     otherwise waste, and gives the story room to be read. */
  .photo-review__bottombar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 20px;
    padding: 12px 20px;
    background: rgba(0, 0, 0, 0.4);
    flex-shrink: 0;
  }

  .photo-review__photo-id {
    display: flex;
    align-items: center;
    gap: 6px;
  }

  .photo-review__id-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-400);
  }

  .photo-review__id-value {
    font-family: var(--font-mono);
    font-size: 13px;
    letter-spacing: 0.03em;
    color: var(--ink-200);
  }

  /* ── Download (visible control; D key also triggers it) ── */
  .photo-review__download-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    font-size: 13px;
    color: var(--ink-200);
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: var(--r-md);
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition);
  }

  .photo-review__download-btn:hover {
    background: rgba(255, 255, 255, 0.16);
    border-color: rgba(255, 255, 255, 0.3);
  }

  .photo-review__download-btn svg {
    width: 15px;
    height: 15px;
  }

  /* ── Selection indicator (click or Space to pick the current photo) ── */
  .selection-indicator {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    border-radius: var(--r-full);
    font-size: 12px;
    font-weight: 500;
    color: var(--ink-200);
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.15);
    font-family: var(--font-ui);
    transition: all 0.15s ease;
    cursor: pointer;
    user-select: none;
  }

  .selection-indicator:hover {
    border-color: rgba(255, 255, 255, 0.35);
    background: rgba(255, 255, 255, 0.1);
  }

  .selection-indicator__check {
    width: 14px;
    height: 14px;
    display: none;
  }

  /* ── Download RAW button (admin final-round review) ── */
  .photo-review__download-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border-radius: var(--r-sm);
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 500;
    color: #fff;
    background: var(--forest-700);
    border: 1px solid var(--forest-500);
    cursor: pointer;
    transition: background 0.15s;
  }

  .photo-review__download-btn:hover { background: var(--forest-900); }
  .photo-review__download-btn svg { width: 14px; height: 14px; }
  .photo-review__download-btn[hidden] { display: none; }

  /* One download link per RAW (a finalist may hold several). The links carry
     the button class, so reset the anchor underline and lay them out in a row. */
  .photo-review__downloads {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
  }

  a.photo-review__download-btn { text-decoration: none; }

  .selection-indicator.is-picked {
    color: #fff;
    border-color: var(--forest-500);
    background: var(--forest-700);
  }

  .selection-indicator.is-picked .selection-indicator__check {
    display: block;
  }

  .selection-indicator.is-error {
    color: var(--danger-50);
    border-color: var(--danger-500);
    background: var(--danger-600);
  }

  /* ── Photo caption (title + story) ── */
  /* order:1 + full-width basis drops the title/story onto their own row below
     the control cluster, so the story spans the full width and reads as prose
     instead of being squeezed into a single ellipsised line between the ID and
     the hints. */
  .photo-review__caption {
    order: 1;
    flex-basis: 100%;
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
  }

  .photo-review__title {
    font-size: 14px;
    font-weight: 500;
    color: var(--ink-100);
  }

  /* The full caption/story: wrap freely, but cap the height so a very long
     story scrolls inside its own area rather than shrinking the photo. */
  .photo-review__subtitle {
    font-size: 12px;
    line-height: 1.5;
    color: var(--ink-200);
    max-height: 8em;
    overflow-y: auto;
    white-space: normal;
  }

  .photo-review__subtitle:empty {
    display: none;
  }

  .photo-review__progress-sep {
    margin: 0 4px;
    color: var(--ink-600);
  }

  /* ── Keyboard hints ── */
  /* margin-left:auto anchors the hints to the far right of the control row now
     that the caption no longer sits between them (it moved to its own row). */
  .photo-review__hints {
    font-size: 11px;
    color: rgba(255, 255, 255, 0.25);
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    margin-left: auto;
  }

  .photo-review__hints kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 20px;
    padding: 0 5px;
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 3px;
    font-family: var(--font-ui);
    font-size: 10px;
    color: rgba(255, 255, 255, 0.4);
    background: rgba(255, 255, 255, 0.05);
  }
}
