      /* ---------- OPEN-MODAL CUT ANIMATION ---------- */
      /* The cut FINISHES right on the hovered card (the stage is pinned to that card's rect) and the
   scrap crumples there too — only the crumpled paper travels to screen-center, where it slowly
   un-crumples (blooms) into the detail modal. */
      .openfx[hidden] {
        display: none;
      }
      .openfx {
        position: fixed;
        inset: 0;
        z-index: 55;
        pointer-events: none;
        background: rgba(6, 4, 2, 0.82);
        backdrop-filter: blur(3px);
        animation: ofxDim 0.12s ease both;
      }
      .openfx.fading {
        animation: ofxUndim 0.42s ease forwards;
      }
      @keyframes ofxDim {
        from {
          opacity: 0;
        }
        to {
          opacity: 1;
        }
      }
      @keyframes ofxUndim {
        to {
          opacity: 0;
        }
      }
      /* stage left/top/width/height + ball travel (--bdx/--bdy) are set inline from the card's rect */
      .ofx-stage {
        position: absolute;
        z-index: 1;
        --accent: var(--gold);
        --cut-start: 50%;
        --cut-dur: 0.4s;
      }
      .ofx-stage.tv {
        --accent: var(--red);
      }
      /* shadow via filter (not box-shadow) so the mask/clip holes below don't clip the lift away */
      .ofx-ticket {
        position: absolute;
        inset: 0;
        z-index: 1;
        filter: drop-shadow(0 16px 26px rgba(0, 0, 0, 0.85));
      }
      .ofx-stub,
      .ofx-body {
        position: absolute;
        top: 0;
        bottom: 0;
      }
      /* body + stub mirror the card's box model exactly: 4px accent border + 46px stub → seam at 50px */
      .ofx-body {
        left: 50px;
        right: 0;
        background: var(--paper);
        border-radius: 0 8px 8px 0;
        transform-origin: 50% 50%;
        overflow: hidden;
        /* real cut-through slit at the seam (left edge), growing top→down with the scissors */
        clip-path: polygon(
          2px 0,
          100% 0,
          100% 100%,
          0 100%,
          0 var(--cut-start),
          2px var(--cut-start)
        );
        /* punch the seam-side notch holes so the dim background shows through */
        -webkit-mask:
          radial-gradient(circle at 0 0, #0000 6.4px, #000 6.6px),
          radial-gradient(circle at 0 100%, #0000 6.4px, #000 6.6px);
        -webkit-mask-composite: source-in;
        mask:
          radial-gradient(circle at 0 0, #0000 6.4px, #000 6.6px),
          radial-gradient(circle at 0 100%, #0000 6.4px, #000 6.6px);
        mask-composite: intersect;
      }
      .ofx-body .main {
        height: 100%;
      }
      .ofx-stub {
        left: 0;
        width: 50px;
        background: var(--paper-2);
        border-radius: 8px 0 0 8px;
        border-left: 4px solid var(--accent);
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 14px 0;
        transform-origin: 50% 60%;
        z-index: 2;
        -webkit-mask:
          radial-gradient(circle at 100% 0, #0000 6.4px, #000 6.6px),
          radial-gradient(circle at 100% 100%, #0000 6.4px, #000 6.6px);
        -webkit-mask-composite: source-in;
        mask:
          radial-gradient(circle at 100% 0, #0000 6.4px, #000 6.6px),
          radial-gradient(circle at 100% 100%, #0000 6.4px, #000 6.6px);
        mask-composite: intersect;
      }
      .ofx-stub::after {
        content: "";
        position: absolute;
        top: 9px;
        bottom: 9px;
        right: -1px;
        width: 2px;
        background-image: linear-gradient(
          to bottom,
          rgba(28, 22, 16, 0.34) 50%,
          transparent 50%
        );
        background-size: 2px 11px;
      }
      .ofx-stage.film .stub-type {
        color: var(--gold-deep);
      }
      .ofx-stage.tv .stub-type {
        color: var(--red);
      }
      .ofx-scissors {
        position: absolute;
        left: 50px;
        top: 50%;
        width: 24px;
        height: 24px;
        color: var(--paper-ink);
        z-index: 4;
        transform: translate(-50%, -50%) rotate(90deg);
        filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.45));
      }
      .ofx-scissors svg {
        width: 100%;
        height: 100%;
      }
      /* the detail modal grows out from behind the main container, expanding to centre-screen.
   Starts scaled (--ms) & translated (--mdx/--mdy) so it's tucked behind the body; ends full-size. */
      .ofx-morph {
        position: absolute;
        z-index: 0;
        background: var(--paper);
        border-radius: 12px;
        border-left: 6px solid var(--gold);
        box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 1);
        opacity: 0;
        transform-origin: 50% 50%;
      }
      .ofx-morph.tv {
        border-left-color: var(--red);
      }
      /* timeline — the cut resumes from the seam's midpoint, where hover paused it */
      .ofx-scissors {
        animation: ofxScissors var(--cut-dur) cubic-bezier(0.5, 0.05, 0.4, 1)
          forwards;
      }
      .ofx-scissors .bld-a {
        animation: snipA 0.2s ease-in-out 3;
      }
      .ofx-scissors .bld-b {
        animation: snipB 0.2s ease-in-out 3;
      }
      .ofx-stub {
        animation: ofxStubFall 0.54s cubic-bezier(0.45, 0.1, 0.7, 1)
          var(--cut-dur) forwards;
      }
      .ofx-body {
        animation:
          ofxBodyCut var(--cut-dur) cubic-bezier(0.5, 0.05, 0.4, 1) forwards,
          ofxBodyFade 0.4s ease-in calc(var(--cut-dur) + 0.5s) forwards;
      }
      .ofx-morph {
        animation: ofxMorph 0.74s cubic-bezier(0.2, 0.78, 0.24, 1)
          calc(var(--cut-dur) + 0.26s) forwards;
      }
      /* the cut resumes from wherever hover left the scissors (--cut-start) and finishes to the bottom */
      @keyframes ofxScissors {
        0% {
          top: var(--cut-start);
          opacity: 1;
        }
        80% {
          opacity: 1;
        }
        100% {
          top: calc(100% + 16px);
          opacity: 0;
        }
      }
      /* the seam slit opens from the resume point down to the bottom — revealing the dim background */
      @keyframes ofxBodyCut {
        from {
          clip-path: polygon(
            2px 0,
            100% 0,
            100% 100%,
            0 100%,
            0 var(--cut-start),
            2px var(--cut-start)
          );
        }
        to {
          clip-path: polygon(
            2px 0,
            100% 0,
            100% 100%,
            0 100%,
            0 100%,
            2px 100%
          );
        }
      }
      @keyframes ofxStubFall {
        0% {
          transform: rotate(0) translate(0, 0);
          opacity: 1;
        }
        30% {
          transform: rotate(-6deg) translate(-3px, 10px);
        }
        100% {
          transform: rotate(-34deg) translate(-60px, 320px);
          opacity: 0;
        }
      }
      @keyframes ofxBodyFade {
        to {
          opacity: 0;
        }
      }
      /* modal-shaped panel emerges from behind the body (--mdx/--mdy/--ms) and expands to full size */
      @keyframes ofxMorph {
        0% {
          opacity: 0;
          transform: translate(var(--mdx, 0), var(--mdy, 0))
            scale(var(--ms, 0.3));
        }
        16% {
          opacity: 1;
        }
        100% {
          opacity: 1;
          transform: none;
        }
      }
      /* the real modal cross-fades in exactly where the morph finished */
      .panel.morphin {
        animation: morphIn 0.34s ease;
      }
      @keyframes morphIn {
        from {
          opacity: 0;
          transform: scale(0.985);
        }
        to {
          opacity: 1;
          transform: none;
        }
      }

