[data-w-portal-embed] {
  position: relative;
  width: 100%;
  height: 100%;
}

[data-w-portal-video] {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
  /* The clip is 1.88:1 and the hero is whatever the viewport happens to be, so
     it is filled rather than fitted: letterbox bars would cut straight across
     the backdrop the copy is set against. Framing is the one thing likely to
     want a per-breakpoint nudge, so it goes through a variable. */
  object-fit: cover;
  object-position: var(--w-portal-focus, 50% 50%);
  pointer-events: none;
  background: #000;
}

[data-w-portal-fade] {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: #000;
  opacity: 0;
  /* Keeps the scroll fade on the compositor instead of repainting a
     full-viewport rect over the video on every frame. */
  will-change: opacity;
  transform: translateZ(0);
}

/* The scrim that keeps the copy legible is now driven off the scroll, so it is
   promoted for the same reason the fade above it is. Scoped to the hero, since
   the later sections share the class and hold theirs still. */
.home_hero-view .section_bg-overlay {
  will-change: opacity;
}

/* Intro copy in the hero is scroll-driven and must stay hidden until the fire
   clip has mostly cleared. Manual animation attrs keep the global script from
   firing a separate entrance on scroll-into-view. */
.home_hero-view .home-intro_component-wrap:not([data-intro-armed]) [data-animation="opacity-in"] {
  opacity: 0;
}

/* The clip is 1.88:1. At full height on a portrait phone `cover` scales it to
   ~1600px wide and shows only the middle ~24%, which cuts the W in half.
   Starting short widens what is visible; the scroll then opens it back out to
   full bleed. One variable drives the whole morph, and the `0` fallback means
   the framed state is already correct on first paint — the script never has to
   run to avoid a flash. */
@media screen and (max-width: 479px) {
  .section_embed {
    background: #000;
  }

  [data-w-portal-embed] {
    /* Where the mask stops being fully opaque. Everything below it ramps to
       transparent, so the clip dissolves into the black behind it instead of
       ending on a cut. At morph 1 the stop reaches the bottom and the mask is
       a no-op, which is what the closing fade at 0.92 needs. */
    --w-portal-mask-stop: calc(58% + 42% * var(--w-portal-morph, 0));
    height: calc(55% + 45% * var(--w-portal-morph, 0));
    -webkit-mask-image: linear-gradient(
      to bottom,
      #000 var(--w-portal-mask-stop),
      transparent 100%
    );
    mask-image: linear-gradient(
      to bottom,
      #000 var(--w-portal-mask-stop),
      transparent 100%
    );
  }

  /* The W sits right of centre in the clip, so the framed state has to look
     further right to hold it whole; the full-bleed state goes back to centre.
     How far right depends on the box the device ends up with, so the script
     solves it and hands the answer over — the literal here is only what the
     first paint uses, sized for a portrait phone with its chrome showing. */
  [data-w-portal-video] {
    --w-portal-focus: calc(
        var(--w-portal-focus-framed, 88%) * (1 - var(--w-portal-morph, 0)) +
          50% * var(--w-portal-morph, 0)
      )
      50%;
  }
}
