/* ==========================================================================
   Home — the room
   ==========================================================================
   The composition is stacked in layers: background, television, tapes, and
   the foreground labels. The layers exist purely to control what sits in
   front of what.
   ========================================================================== */
.room {
  position: relative;
  block-size: 100vh;
  block-size: 100dvh;
  overflow: hidden;
}

/* Applied by JS (js/entrance.js) at boot, before the loader lifts, and removed
   by the entrance as each component enters. Opacity only — never in the HTML,
   so a no-JS visit renders everything immediately, and a JS failure can only
   leave things visible, never stuck hidden. */
.is-staged { opacity: 0; }

/* Every layer is a full-viewport box, so an upper one would otherwise
   swallow every click meant for the layer beneath it — which is exactly what
   the chrome layer was doing to the tapes and to the television's power
   controls. The boxes are spacing only; their contents take the hits. */
.plane {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.plane > * { pointer-events: auto; }

.plane--bg    { z-index: var(--z-plane-bg); }
.plane--tv    { z-index: var(--z-plane-tv); }
.plane--tapes { z-index: var(--z-plane-tapes); }
.plane--fore  { z-index: var(--z-plane-fore); }

/* Decorative only — never a hit target, whatever the rule above says. */
.plane--bg > * { pointer-events: none; }

/* Atmosphere. A soft pool of light around the set, and a faint lift at the
   top of the frame.

   Both are weaker than they were: the page ground now falls off downward to
   match the video, and the old bottom-weighted pool was pushing light back
   into exactly the region the measurement says should be darkest. What is
   left is only what the television itself would throw. */
.room__ambient {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(52% 34% at 50% 88%, rgba(74, 120, 200, 0.055), transparent 74%),
    radial-gradient(120% 70% at 50% 6%, rgba(190, 205, 235, 0.022), transparent 72%);
  pointer-events: none;
}

/* ==========================================================================
   Masthead
   ========================================================================== */
.masthead {
  position: absolute;
  inset-block-start: calc(54 * var(--u));
  inset-inline: calc(70 * var(--u));
  z-index: var(--z-chrome);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}

/* 81x42, not the 81x41 Figma slot: the source is 300x156 (ratio 1.923) and
   the asset's own proportions win over the node box. */
.masthead__logo {
  display: block;
  inline-size: calc(81 * var(--u));
  block-size: calc(42 * var(--u));
}
.masthead__logo img { inline-size: 100%; block-size: 100%; }

/* The nav: two icon buttons (css/nav.css), right edge at x=1370, top level
   with the logo at y=54 — the masthead is already inset 70 and top 54. The
   same bar as the case-study header (.work-head__nav). */
.nav {
  display: flex;
  gap: calc(16 * var(--u));
}

/* ==========================================================================
   Project readout — two slots that never move
   ==========================================================================
   Contents swap as the hovered tape changes; the boxes stay anchored for the
   whole session. Both are absolutely positioned, grow in one direction only
   and reserve their height, so no content length can shift the layout.
   IRONHOLLOW (2025) and SOLN (2025) are very different widths.
   ========================================================================== */
.readout__title {
  position: absolute;
  inset-inline-start: calc(70 * var(--u));
  inset-block-end: calc(80.8 * var(--us));
  margin: 0;
  /* Project title: Chivo Bold at a fixed 18px (feedback 2026-09-01). */
  font-family: var(--font-chivo);
  font-weight: 700;
  font-size: 18px;
  line-height: var(--lh-heading);
  letter-spacing: normal;
  white-space: nowrap;
}

.readout__role {
  position: absolute;
  inset-inline-end: calc(70 * var(--u));
  inset-block-end: calc(61.6 * var(--us));
  margin: 0;
  font-size: clamp(11px, calc(12 * var(--u)), 12px);
  line-height: var(--lh-stacked);
  letter-spacing: var(--ls-mono-ui);
  text-transform: uppercase;
  text-align: end;
  white-space: nowrap;
  /* Two lines reserved even for a one-line role, so the block never changes
     height. */
  block-size: calc(2 * var(--lh-stacked) * 1em);
}

/* Hidden by default. With no tape under the pointer there is no project to
   name, so both slots sit empty — the resting state is blank, not the top
   project. .is-visible (set by js/tapes.js while a tape is hovered or focused)
   fades them in. is-swapping still forces 0 for the between-tape dissolve, so it
   stays AFTER .is-visible here to win while both are set.

   The swap is a stepped dissolve — four poses over 333ms — not a crossfade. It
   belongs to the same motion language as everything else, and it is the one
   place opacity is stepped rather than continuous, because here the change is
   authored content rather than atmosphere. The same transition carries the
   show/hide fade. */
.readout__title, .readout__role {
  opacity: 0;
  transition: opacity var(--dur-swap) var(--step-swap);
}
.readout.is-visible .readout__title,
.readout.is-visible .readout__role { opacity: 1; }
.readout.is-swapping .readout__title,
.readout.is-swapping .readout__role { opacity: 0; }
