/* ==========================================================================
   WREN — placeholders.css
   The red box system (CLAUDE.md §5). Every media slot is a signal-red box
   when no real file exists in /assets. Slots start neutral-dark while the
   file is tried, so real media never flashes red first. Placeholders receive
   every animation the real media will get — swapping content changes zero
   animation code.
   ========================================================================== */

/* Base slot: neutral tunnel-dark while the real file is being tried.
   aspect-ratio is set per-slot by placeholders.js from media.json. */
.ph {
  position: relative;
  width: 100%;
  background: var(--tunnel-lift);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

/* No file yet (load failed) or no media.json entry → signal red */
.ph--empty,
.ph--error {
  background: var(--signal);
  box-shadow: inset 0 0 0 1px var(--signal-inset);
}

/* Top-left: slot id + declared ratio */
.ph__meta {
  position: absolute;
  top: 6px;
  left: 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: var(--tracking-mono);
  color: #fff;
  opacity: 0.9;
  text-transform: uppercase;
  pointer-events: none;
}

/* Top-right: ▶ VIDEO / ♪ AUDIO badge */
.ph__badge {
  position: absolute;
  top: 6px;
  right: 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: var(--tracking-mono);
  color: var(--signal);
  background: #fff;
  padding: 1px 6px;
  pointer-events: none;
}

/* Center: the full Midjourney prompt — selectable, click-to-copy */
.ph__prompt {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  letter-spacing: var(--tracking-mono);
  color: #fff;
  max-width: 80%;
  max-height: 78%;
  overflow: hidden;
  text-align: center;
  user-select: text;
  -webkit-user-select: text;
  cursor: copy;
}

.ph__prompt:focus-visible {
  outline-color: #fff;
}

/* Tight slots: hide the prompt when there's no room, keep the meta */
.ph--tight .ph__prompt {
  display: none;
}

/* "COPIED" flash after click-to-copy */
.ph__copied {
  position: absolute;
  bottom: 8px;
  left: 50%;
  transform: translate(-50%, 4px);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  color: var(--signal);
  background: #fff;
  padding: 2px 8px;
  opacity: 0;
  transition: opacity 0.2s var(--ease-house), transform 0.2s var(--ease-house);
  pointer-events: none;
}

.ph__copied.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* Real media swapped in — identical box, zero layout shift */
.ph--loaded {
  background: var(--tunnel-lift);
  box-shadow: none;
}

.ph--loaded .ph__meta,
.ph--loaded .ph__badge,
.ph--loaded .ph__prompt,
.ph--loaded .ph__copied {
  display: none;
}

.ph__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* soft arrival over the neutral box — no hard pop when the file lands */
  animation: ph-media-in 0.4s var(--ease-house) both;
}

@keyframes ph-media-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .ph__media {
    animation: none;
  }
}

/* Missing media.json entry — loud, unmissable */
.ph--error {
  outline: 2px dashed #fff;
  outline-offset: -6px;
}
