/* Floating image — V0.1 Why Co.Si: 280×310 at x=50, radius 20, top-aligned with the first heading.
   float-media.js sets --fm-span (height of the run of Text/Quote modules it floats beside)
   and --fm-offset (that run's top padding). The block overlays the run and takes no room. */
.block--float-media {
  --fm-w: 280px;    /* V0.1 */
  --fm-ratio: 28 / 31; /* V0.1 280×310 */
  position: relative; z-index: 1;
  background: none;
  pointer-events: none;
}
.block--float-media.float-media--square { --fm-ratio: 1; }
.block--float-media.float-media--landscape { --fm-ratio: 4 / 3; }

.block--float-media .float-media__media { position: relative; width: var(--fm-w); max-width: 100%; aspect-ratio: var(--fm-ratio); }
/* Several files stack in one frame; float-media.js moves .is-active and they cross-dissolve. */
.block--float-media .float-media__layer { position: absolute; inset: 0; opacity: 0; transition: opacity var(--dur-slow) var(--ease-in-out); }
.block--float-media .float-media__layer.is-active { opacity: 1; }

@media (min-width: 1024px) {
  /* Takes no room from the first paint, before the JS has measured the run, so the run
     never jumps up when it starts floating (was CLS 0.168 on Why, qa-sweep 2026-09-22).
     Only when a run follows: float-media.js does nothing without one. */
  .js .block--float-media:has(+ .block--quote, + .block--text.text--text) {
    height: var(--fm-span, 0px);
    margin-bottom: calc(var(--fm-span, 0px) * -1);
  }
  .block--float-media.is-floating .float-media { height: 100%; grid-template-rows: 100%; }
  .block--float-media.is-floating .float-media__col { padding-top: var(--fm-offset, 0px); }
  .block--float-media.is-floating .float-media__sticky {
    position: sticky;
    /* Float at the viewport's middle, never under the nav. */
    top: max(calc(var(--nav-height) + var(--space-24)), calc(50vh - var(--fm-w) / (var(--fm-ratio)) / 2));
  }
  .block--float-media.is-floating .float-media__media { will-change: opacity, transform; }
  /* It takes no room in the flow, so the module after an eyebrow-only page heading
     keeps page-hero's "no top padding" rule. */
  .js .block--page-hero + .block--float-media:has(+ .block--quote, + .block--text.text--text) + .block { padding-top: 0; }
}

@media (max-width: 1023px) {
  .block--float-media { --fm-w: min(240px, 60vw); padding-top: var(--space-40); }
}

@media (max-width: 767px) {
  /* The viewfinder (mobile experience, 2026-09-30): the image opens the page under the pill,
     full-bleed, then sticks to the top of the screen while the copy and quotes scroll under
     it, dissolving through its files and fading out as the run ends: the desktop float's
     own logic (float-media.js). The block is the window's height plus the run's, pulled back
     over the run, so the window stays stuck for exactly the run and the copy starts right
     under it. Tablets (768–1023) keep the inline images. */
  .block--float-media { --fm-w: auto; --fm-ratio: 3 / 2; padding-top: 0; }
  .block--float-media .float-media__media { max-width: none; margin-inline: calc(-1 * var(--gutter)); }
  .block--float-media .float-media__layer { border-radius: 0; }
  .js .block--float-media.is-floating:has(+ .block--quote, + .block--text.text--text) {
    height: calc(var(--fm-vf, 0px) + var(--fm-span, 0px));
    margin-bottom: calc(var(--fm-span, 0px) * -1);
  }
  .block--float-media.is-floating .float-media { height: 100%; grid-template-rows: 100%; } /* the column is as tall as the block, so the window can stick through the run */
  .block--float-media.is-floating .float-media__sticky { position: sticky; top: 0; z-index: 3; }
  .block--float-media.is-floating .float-media__media { will-change: opacity, transform; }
}
