/* ============================================================================
   reel.css: /projects as a full screen reel (cinematic upgrade, 2026-09-25).

   Loaded after pages.css by /projects only. The page is:

     the mission select   (pages.css, unchanged, shared with /welcome)
     the title card       .reel-title: CREATED BY TOAI, set big
     the reel             .mission-deck: one full screen panel per project

   Every panel is the entry's own markup (kicker, rule, name, the link with
   its picture, the note) plus its headline number and one line. The link is
   the whole picture, so the whole panel opens the case.

   Two modes, one markup:

     stacked   the default, and what no JS or prefers-reduced-motion gets:
               the panels are full screen sections one after another.
     pinned    .mission.is-pinned (projects.js): the deck is a sticky screen
               inside a tall scroll block, every panel owns one viewport of
               scroll, and the change from one to the next is a cut, not a
               slide. Native scroll positions only: it works under a phone's
               own scroll and under a smooth-scroll library alike, and it
               never snaps.
   ========================================================================== */

.mission {
  --reel-pad: 72px;
  --reel-top: 108px;
  --reel-bottom: 64px;
  --reel-display: var(--font-display, 'Orbitron', sans-serif);
  --reel-label: var(--font-label, 'Share Tech Mono', monospace);
  --reel-body: var(--font-body, 'DM Mono', monospace);
  --reel-accent: var(--cyan-hot, #00f5ff);
  --reel-ink: rgba(7, 7, 7, 0.9);
}

@media (max-width: 991px) {
  .mission {
    --reel-pad: 40px;
    --reel-top: 96px;
  }
}

@media (max-width: 767px) {
  .mission {
    --reel-pad: 20px;
    --reel-top: 84px;
    /* clear the Instagram button and the scroll cue, and on a phone whose
       toolbar is showing, the strip of the large viewport it covers */
    --reel-bottom: 104px;
  }

  @supports (height: 100lvh) {
    .mission {
      --reel-bottom: calc(104px + (100lvh - 100svh));
    }
  }
}

/* ---- the stage ---------------------------------------------------------- */

.mission-stage {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
}

/*
 * CLOSE stays on screen from the title card to the last panel: it is sticky
 * inside the stage, drawn first by `order` and taking no height, so nothing
 * moves in the markup. Left of the site menu's button, where the live page
 * has it.
 */
.mission-stage > .room-btn--corner {
  order: -1;
  position: sticky;
  top: 20px;
  right: auto;
  align-self: flex-end;
  z-index: 30;
  height: 34px;
  margin: 20px 200px -54px 0;
}

@media (max-width: 991px) {
  .mission-stage > .room-btn--corner {
    margin-right: 90px;
  }
}

@media (max-width: 767px) {
  .mission-stage > .room-btn--corner {
    top: 12px;
    margin: 12px 70px -46px 0;
  }
}

/* ---- the title card ----------------------------------------------------- */

.reel-title {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-rows: 1fr auto auto 1fr auto;
  justify-items: center;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  padding: var(--reel-top) var(--reel-pad) 44px;
  text-align: center;
  overflow: hidden;
}

/* It holds while the first panel slides over it. */
.mission.is-pinned .reel-title {
  position: sticky;
  top: 0;
}

.reel-title::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(ellipse 60% 48% at 50% 50%, rgba(0, 245, 255, 0.07), transparent 70%),
    linear-gradient(180deg, rgba(7, 7, 7, 0.2), rgba(7, 7, 7, 0.55));
}

.reel-title .mission-head {
  display: contents;
}

.reel-title .mission-mark {
  position: relative;
  grid-row: 2;
  grid-column: 1;
  width: 132px;
  height: 112px;
}

/* The corner bracket the live page drew with a Lottie plus eight empty divs:
   four corner ticks round the brand mark, no markup, no JSON. */
.mission-mark::before {
  content: '';
  position: absolute;
  inset: 0;
  --tick: rgba(255, 255, 255, 0.55);
  background-image:
    linear-gradient(var(--tick), var(--tick)), linear-gradient(var(--tick), var(--tick)),
    linear-gradient(var(--tick), var(--tick)), linear-gradient(var(--tick), var(--tick)),
    linear-gradient(var(--tick), var(--tick)), linear-gradient(var(--tick), var(--tick)),
    linear-gradient(var(--tick), var(--tick)), linear-gradient(var(--tick), var(--tick));
  background-repeat: no-repeat;
  background-size: 16px 1px, 1px 16px, 16px 1px, 1px 16px, 16px 1px, 1px 16px, 16px 1px, 1px 16px;
  background-position:
    left top, left top,
    right top, right top,
    right bottom, right bottom,
    left bottom, left bottom;
}

.reel-title .mission-logo {
  grid-row: 2;
  grid-column: 1;
  width: 104px;
  height: auto;
  margin: 0;
  mix-blend-mode: lighten;
}

.reel-title .mission-title {
  grid-row: 3;
  justify-self: center;
  width: auto;
  max-width: 11ch;
  margin: 40px 0 0;
  font-family: var(--reel-display);
  font-size: var(--fs-hero, clamp(44px, 7vw, 120px));
  font-weight: 700;
  line-height: 0.98;
  letter-spacing: var(--tracking-display, 0.02em);
  color: var(--white);
  text-transform: uppercase;
  text-wrap: balance;
  text-shadow: 0 0 48px rgba(0, 245, 255, 0.22);
}

.reel-title .mission-hint {
  grid-row: 5;
  margin: 0;
  font-family: var(--reel-label);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.32em;
  color: rgba(242, 242, 245, 0.62);
}

/* ---- a panel ------------------------------------------------------------ */

.mission-deck {
  position: relative;
  z-index: 2;
  background: var(--void);
}

.mission-card {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  grid-template-columns: var(--reel-pad) minmax(0, 1fr) var(--reel-pad);
  grid-template-rows: var(--reel-top) auto 1fr auto auto auto auto var(--reel-bottom);
  overflow: hidden;
  isolation: isolate;
  background: var(--void);
}

/* The head's three parts are laid out in the panel's own grid. */
.mission-card-head {
  display: contents;
}

/* The picture (and the film, on the website builds) is the link. */
.mission-shot {
  grid-area: 1 / 1 / -1 / -1;
  position: relative;
  z-index: 0;
  display: block;
  overflow: hidden;
  background: var(--void);
  text-decoration: none;
  transition: transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* A mouse leaning on the picture pushes it a little further in. */
.mission-shot:hover,
.mission-shot:focus-visible {
  transform: scale(1.015);
}

.mission-shot:focus-visible {
  outline: 2px solid var(--reel-accent);
  outline-offset: -8px;
}

.mission-img,
.reel-video {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform-origin: 50% 55%;
}

.mission-card.has-video .mission-img {
  display: none;
}

.reel-video {
  background: var(--void);
}

/* per picture framing on a tall screen, where cover keeps only the middle */
.mission-card[data-reel='lashsalon'] .mission-img { object-position: 38% 50%; }
.mission-card[data-reel='autobodyshop'] .mission-img { object-position: 45% 50%; }
.mission-card[data-reel='hairstylist'] .mission-img { object-position: 30% 50%; }
/* the music artist's loop is one landscape cut: on a tall screen keep the
   figure, who stands right of the middle, in the frame (still and film) */
.mission-card[data-reel='music-artist'] :is(.mission-img, .reel-video) { object-position: 64% 50%; }

/* The legibility veil: UI over the picture, never baked into it. */
.mission-card::after {
  content: '';
  grid-area: 1 / 1 / -1 / -1;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(7, 7, 7, 0.62) 0%, rgba(7, 7, 7, 0) 20%),
    linear-gradient(0deg, rgba(7, 7, 7, 0.9) 0%, rgba(7, 7, 7, 0.55) 34%, rgba(7, 7, 7, 0) 64%),
    linear-gradient(90deg, rgba(7, 7, 7, 0.5) 0%, rgba(7, 7, 7, 0) 58%);
}

/* a live site has its own headline under ours: a deeper veil there (and on
   its still, .has-film, before the film has taken over) */
.mission-card.has-film::after,
.mission-card.has-video::after {
  background:
    linear-gradient(180deg, rgba(7, 7, 7, 0.66) 0%, rgba(7, 7, 7, 0) 22%),
    linear-gradient(0deg, rgba(7, 7, 7, 0.94) 0%, rgba(7, 7, 7, 0.72) 40%, rgba(7, 7, 7, 0.15) 72%),
    linear-gradient(90deg, rgba(7, 7, 7, 0.72) 0%, rgba(7, 7, 7, 0.2) 55%, rgba(7, 7, 7, 0) 75%);
}

/* the words sit over the link and let every click through to it */
.mission-kicker,
.mission-rule,
.mission-name,
.reel-figure,
.mission-note,
.reel-now {
  position: relative;
  z-index: 2;
  pointer-events: none;
}

/* the slate: 01 / 07 and the kicker */
.mission-kicker {
  grid-area: 2 / 2;
  display: flex;
  align-items: baseline;
  gap: 14px;
  font-family: var(--reel-label);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0.3em;
  color: rgba(242, 242, 245, 0.78);
  text-transform: uppercase;
}

.mission-kicker[data-idx]::before {
  content: attr(data-idx);
  color: var(--reel-accent);
  letter-spacing: 0.2em;
}

.mission-rule {
  grid-area: 4 / 2;
  width: 56px;
  height: 1px;
  margin-bottom: 18px;
  background: var(--reel-accent);
  box-shadow: 0 0 12px rgba(0, 245, 255, 0.6);
}

.mission-name {
  grid-area: 5 / 2;
  font-family: var(--reel-display);
  font-size: clamp(20px, 2.4vw, 38px);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: 0.06em;
  color: var(--white);
  text-transform: uppercase;
}

/* The headline number and its line. projects.js sizes the number to the
   panel's width once the face has loaded; this is the fallback. */
.reel-figure {
  grid-area: 6 / 2;
  display: grid;
  justify-items: start;
  margin: 10px 0 0;
}

.reel-num {
  display: block;
  font-family: var(--reel-display);
  font-size: clamp(48px, 14vw, 230px);
  font-weight: 700;
  line-height: 0.92;
  letter-spacing: -0.01em;
  color: #fff;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 60px rgba(0, 245, 255, 0.28), 0 2px 18px rgba(0, 0, 0, 0.45);
  white-space: nowrap;
}

.reel-line {
  display: block;
  margin-top: 14px;
  font-family: var(--reel-label);
  font-size: clamp(12px, 1.05vw, 15px);
  letter-spacing: 0.24em;
  color: var(--reel-accent);
  text-transform: uppercase;
}

/* the entry's note, and the call it opens with */
.mission-note {
  grid-area: 7 / 2;
  align-self: start;
  width: auto;
  max-width: 50ch;
  margin-top: 22px;
  font-family: var(--reel-body);
  font-size: 15px;
  line-height: 1.6;
  text-align: left;
  color: rgba(242, 242, 245, 0.86);
}

.reel-cta {
  display: flex;
  align-items: center;
  gap: 12px;
  width: max-content;
  margin-bottom: 8px;
  font-family: var(--reel-label);
  font-size: 12px;
  letter-spacing: 0.3em;
  color: #fff;
}

/* a drawn arrow, so no glyph can go missing */
.reel-cta::after {
  content: '';
  width: 34px;
  height: 1px;
  background: currentColor;
  box-shadow: 0 0 10px rgba(0, 245, 255, 0.5);
  transition: width 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
}

@media (hover: hover) and (pointer: fine) {
  .mission-card:hover .reel-cta {
    color: var(--reel-accent);
  }

  .mission-card:hover .reel-cta::after {
    width: 58px;
  }
}

/* "now showing" over the website builds: which live site is on screen */
.reel-now {
  grid-area: 2 / 2;
  justify-self: end;
  display: grid;
  justify-items: end;
  gap: 8px;
  margin: 0;
  font-family: var(--reel-label);
  font-size: 11px;
  letter-spacing: 0.28em;
  color: rgba(242, 242, 245, 0.72);
  text-transform: uppercase;
  text-align: right;
}

.reel-now b {
  font-weight: 400;
  color: #fff;
}

.reel-now i {
  font-style: normal;
  color: var(--reel-accent);
}

.reel-now-bar {
  display: block;
  width: 120px;
  height: 1px;
  background: rgba(242, 242, 245, 0.2);
  overflow: hidden;
}

.reel-now-bar::before {
  content: '';
  display: block;
  width: 100%;
  height: 100%;
  background: var(--reel-accent);
  transform-origin: 0 50%;
  transform: scaleX(0);
}

.reel-now.is-running .reel-now-bar::before {
  animation: reelClip var(--clip-dur, 10s) linear both;
}

.reel-now.is-paused .reel-now-bar::before {
  animation-play-state: paused;
}

@keyframes reelClip {
  to { transform: scaleX(1); }
}

@media (max-width: 767px) {
  .mission-kicker {
    font-size: 11px;
    letter-spacing: 0.24em;
  }

  .mission-note {
    margin-top: 16px;
    font-size: 13.5px;
    line-height: 1.55;
  }

  .reel-cta {
    font-size: 11px;
  }

  .reel-line {
    margin-top: 10px;
    font-size: 11px;
    letter-spacing: 0.2em;
  }

  /* on a phone the site name moves under the slate, clear of the menu */
  .reel-now {
    grid-area: 3 / 2;
    align-self: start;
    justify-self: start;
    justify-items: start;
    margin-top: 14px;
    text-align: left;
  }
}

/* ---- pinned: the reel ----------------------------------------------------- */

.mission.is-pinned .mission-scroll {
  position: relative;
  z-index: 2;
  height: calc((var(--reel-n, 7) + 1) * 100vh);
}

@supports (height: 100lvh) {
  .mission.is-pinned .mission-scroll {
    height: calc((var(--reel-n, 7) + 1) * 100lvh);
  }
}

.mission.is-pinned .mission-deck {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}

@supports (height: 100lvh) {
  .mission.is-pinned .mission-deck {
    height: 100lvh;
  }
}

.mission.is-pinned .mission-card {
  position: absolute;
  inset: 0;
  min-height: 0;
  height: 100%;
  opacity: 0;
  pointer-events: none;
  z-index: 0;
}

/* Only the panels next to the live one are drawn: the rest hold no decoded
   picture and fetch nothing until the reel comes near them. */
.mission.is-pinned .mission-card.is-far {
  display: none;
}

.mission.is-pinned .mission-card.is-prev {
  opacity: 1;
  z-index: 1;
}

.mission.is-pinned .mission-card.is-live {
  opacity: 1;
  pointer-events: auto;
  z-index: 2;
}

/* the media moves on the compositor */
.mission.is-pinned .mission-img,
.mission.is-pinned .reel-video {
  will-change: transform;
}

/*
 * The cut. The new shot is on screen in a sixth of a second, its camera
 * already settling (a push that lands), a flash of light across the frame
 * as it comes up, and the words come in behind it in order.
 */
.mission.is-pinned .mission-card.is-cut {
  animation: reelCutIn 0.16s linear both;
}

.mission.is-pinned .mission-card.is-cut .mission-shot > * {
  animation: reelSettle 1.1s cubic-bezier(0.16, 0.84, 0.24, 1) both;
}

.mission.is-pinned .mission-card.is-cut::before {
  content: '';
  grid-area: 1 / 1 / -1 / -1;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(90deg, rgba(0, 245, 255, 0) 0%, rgba(0, 245, 255, 0.16) 45%, rgba(255, 255, 255, 0.22) 50%, rgba(226, 24, 189, 0.12) 55%, rgba(226, 24, 189, 0) 100%);
  animation: reelFlash 0.42s ease-out both;
}

.mission.is-pinned .mission-card.is-cut .mission-kicker,
.mission.is-pinned .mission-card.is-cut .reel-now,
.mission.is-pinned .mission-card.is-cut .mission-rule,
.mission.is-pinned .mission-card.is-cut .mission-name,
.mission.is-pinned .mission-card.is-cut .reel-line,
.mission.is-pinned .mission-card.is-cut .mission-note {
  animation: reelRise 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

.mission.is-pinned .mission-card.is-cut .mission-kicker,
.mission.is-pinned .mission-card.is-cut .reel-now { animation-delay: 0.08s; }
.mission.is-pinned .mission-card.is-cut .mission-rule { animation-delay: 0.14s; }
.mission.is-pinned .mission-card.is-cut .mission-name { animation-delay: 0.18s; }
.mission.is-pinned .mission-card.is-cut .reel-line { animation-delay: 0.3s; }
.mission.is-pinned .mission-card.is-cut .mission-note { animation-delay: 0.38s; }

@keyframes reelCutIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes reelSettle {
  from { scale: 1.07; }
  to { scale: 1; }
}

@keyframes reelFlash {
  0% { opacity: 1; transform: translateX(-30%); }
  100% { opacity: 0; transform: translateX(30%); }
}

@keyframes reelRise {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .mission-shot,
  .reel-cta::after {
    transition: none;
  }

  .mission-shot:hover,
  .mission-shot:focus-visible {
    transform: none;
  }

  .reel-now.is-running .reel-now-bar::before {
    animation: none;
  }
}
