/* ============================================================
   AMALAB — scaled-journey.css
   Scroll-driven SCALED section (methode-scaled.html only).
   Light paper-alt band (the entry-points loop above it carries
   the navy). Left: sticky white frame, vertically centred, with
   the active phase name overlaid at its bottom edge; the letter
   videos scrub with scroll behind it. Right: phase content in
   white cards. Motion communicates progress — nothing decorative.
   ============================================================ */

.journey {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: clamp(32px, 5vw, 80px);
  align-items: start;
}

/* This section overrides the page's alternating paper-2 band: the
   heading and the sticky white frame both read best on true white. */
#phases { background: var(--white); }

/* ---------- Sticky stage — centred in the viewport ---------- */
.journey-stage {
  position: sticky;
  top: var(--nav-h);
  height: calc(100vh - var(--nav-h));
  height: calc(100svh - var(--nav-h));
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.journey-stage-inner {
  /* frame + caption + rail stay together; cap so short viewports
     never clip the caption */
  width: min(100%, max(160px, calc(100svh - var(--nav-h) - 200px)));
  margin-inline: auto;
}
.journey-frame {
  position: relative;
  aspect-ratio: 1;
  background: var(--white);
  border-radius: var(--radius-card);
  /* no shadow — the frame sits flat on the section, edge marked only
     by the corner radius and the white-on-white background */
  overflow: hidden;
  /* Bar + name sized against THIS box, not the viewport — see .sh-frame in
     scaled-home.css for the full reasoning. The letter artwork leaves a 20.2%
     bottom margin; a vw-driven bar reached 19.5% at 768px, leaving under 2px
     of air under the glyph's foot. 16.5% is constant and safe at every size,
     and it also keeps "Automate." inside a 160px landscape card. */
  --jt-item-h: clamp(1.25rem, 16.5cqi, 5.25rem);
  container-type: inline-size;
}
.journey-frame video,
.journey-frame .journey-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  /* Hard cut, no fade. Re-encode drift between the boundary frames of
     consecutive morph clips makes any opacity blend read as a visible
     "missing middle" frame; a discrete swap on matched boundary frames
     is the only reliable seam. Posters still fade in below. */
  transition: none;
}
.journey-frame .journey-poster {
  transition: opacity 220ms var(--ease-out);
}
.journey-frame video.is-active,
.journey-frame .journey-poster.is-active { opacity: 1; }

/* Without JS the frame still shows the framework's first state */
html:not(.js) .journey-frame .journey-poster--s { opacity: 1; }

/* ---------- Caption : phase name as a vertical word carousel ----------
   A solid white bar on the frame's bottom edge — no gradient wash over
   the footage. `.jt-caption` is the opaque backdrop (never masked, so it
   stays flat white); `.jt-viewport` is the clipping window on top of it,
   faded at its own top edge so a name sliding out doesn't hard-cut — it
   dissolves into the white first. The six names sit in one column inside
   `.jt-track`, sliding like a reel. Position and rate are driven from JS
   with the exact same eased progress that scrubs the video, so the word
   change and the letter morph read as one motion. */
.jt-caption {
  position: absolute;
  inset: auto 0 0 0;
  height: var(--jt-item-h);
  background: var(--white);
  z-index: 2;
}
.jt-viewport {
  position: absolute;
  inset: 0;
  display: flex;
  justify-content: center;
  overflow: hidden;
  /* Fade band tightened + pulled in toward the text. Top fade pushed
     up (was 22% → 15%) so capital-letter cap height clears the fade
     zone. Bottom fade stays at 85%–93% so descenders still fit. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, transparent 15%, #000 23%, #000 85%, transparent 93%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, transparent 15%, #000 23%, #000 85%, transparent 93%, transparent 100%);
}
.jt-track {
  width: 100%;
  display: flex;
  flex-direction: column;
  will-change: transform;
}
.jt-name {
  height: var(--jt-item-h);
  width: 100%;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 600;
  /* 60% of the bar — see .sh-name in scaled-home.css. */
  font-size: clamp(0.75rem, 9.9cqi, 3.25rem);
  line-height: 1;
  color: var(--navy);
}
.jt-name .dot { color: var(--orange); }

/* ---------- Caption : descriptor + index ---------- */
/* Caption row spans the full frame width; the descriptor centers on
   the same vertical axis as the Scan/Coach word in the frame above,
   and the index sits absolutely pinned to the right edge. */
.journey-caption {
  position: relative;
  margin-top: var(--s-5);
  height: 1.4em;
}
.journey-labels {
  position: absolute;
  inset: 0;
  display: flex;
  justify-content: center;
  align-items: baseline;
}
.journey-label {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  display: flex;
  align-items: baseline;
  justify-content: center;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 260ms var(--ease-out), transform 260ms var(--ease-out);
  pointer-events: none;
}
.journey-label.is-active { opacity: 1; transform: none; }
.journey-label .sub {
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--teal);
  /* manual nudge — pull descriptor text slightly off-axis toward the left
     relative to the Scan/Coach word in the frame above */
  transform: translateX(-2px);
}
.journey-index {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: var(--step-mono);
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--fg-muted);
}
.journey-index-num {
  font-weight: 600;
  color: var(--orange);
}

/* ---------- Progress rail : S — C — A — L — E — D ---------- */
.journey-rail {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-top: var(--s-4);
}
.journey-rail .rail-letter {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9375rem;
  line-height: 1;
  color: var(--fg-muted);
  transition: color var(--t-ui) var(--ease-out);
}
.journey-rail .rail-letter.is-active { color: var(--orange); }
.journey-rail .rail-letter.is-done { color: var(--navy); }
.journey-rail .rail-track {
  flex: 1;
  height: 1px;
  background: var(--border);
  overflow: hidden;
}
.journey-rail .rail-track .rail-fill {
  display: block;
  height: 100%;
  background: var(--teal);
  transform: scaleX(0);
  transform-origin: left center;
}

/* ---------- Phase panels — paper-2 cards on the white section ---------- */
.journey-phases {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(64px, 14vh, 160px);
  padding-block: clamp(32px, 8vh, 96px);
}
.journey-phase {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: clamp(28px, 4vw, 48px);
  box-shadow: var(--shadow-card);
  transition: opacity 360ms var(--ease-out), box-shadow 360ms var(--ease-out);
}
html.js .journey-phase.is-muted { opacity: 0.6; }
.journey-phase.is-active { box-shadow: var(--shadow-card-hover); }

.journey-phase-head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-4);
}
.journey-phase-head .chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-btn);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--navy);
  background: var(--white);
  transition: background var(--t-ui) var(--ease-out),
              color var(--t-ui) var(--ease-out),
              border-color var(--t-ui) var(--ease-out);
}
.journey-phase.is-active .journey-phase-head .chip {
  background: var(--navy);
  border-color: var(--navy);
  color: var(--paper);
}
.journey-phase-head .mono { color: var(--teal); }
.journey-phase h3 { margin-bottom: var(--s-4); max-width: 24ch; }
.journey-phase p + p { margin-top: var(--s-3); }
.journey-phase .deliv {
  margin-top: var(--s-6);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: var(--s-5);
}
.journey-phase .deliv .mono { color: var(--teal); display: block; margin-bottom: var(--s-4); }

/* Defend is the enveloping layer, not a last step — it keeps its
   foundation treatment (teal top rule) */
.journey-phase--defend { border-top: 2px solid var(--teal); }

/* ---------- Tablet / mobile : compact sticky stage on top ---------- */
@media (max-width: 900px) {
  .journey { grid-template-columns: 1fr; gap: 0; }
  .journey-stage {
    top: var(--nav-h);
    height: auto;
    z-index: 5;
    background: var(--bg-alt);
    padding-block: var(--s-3) var(--s-4);
    border-bottom: 1px solid var(--border);
    display: block;
  }
  .journey-stage-inner {
    width: min(100%, 420px);
    margin-inline: auto;
  }
  .journey-frame {
    height: clamp(160px, 26vh, 280px);
    width: auto;
    aspect-ratio: 1;
    margin-inline: auto;
    /* No --jt-item-h / .jt-name override: both are container-relative on
       .journey-frame, so they track this smaller frame on their own. */
  }
  .journey-caption { margin-top: var(--s-3); }
  .journey-rail { margin-top: var(--s-3); }
  .journey-phases {
    gap: clamp(40px, 8vh, 80px);
    padding-block: var(--s-6) var(--s-8);
  }
  .journey-phase { padding: clamp(20px, 5vw, 32px); }
}

/* Wide-and-short windows above the mobile breakpoint (a Pro Max in landscape
   reports 932×430): the height-derived cap belongs to the frame, not to the
   whole stage — at its 160px floor the box was narrower than the longest
   descriptor ("INDUSTRIALISATION", 168px), which then overhung it. */
@media (min-width: 901px) and (max-height: 620px) {
  .journey-stage-inner { width: min(100%, 420px); }
  .journey-frame {
    width: max(140px, min(100%, calc(100svh - var(--nav-h) - 200px)));
    margin-inline: auto;
  }
}

/* ---------- Landscape phones ----------
   The sticky stage (frame + caption + rail) stands ~250px; a landscape phone
   offers ~318px below the header, so the phase copy was reading through a
   70px slot. Below this height the stage scrolls with the page instead of
   pinning, and the content gets the whole screen. */
@media (max-width: 900px) and (max-height: 520px) {
  .journey-stage {
    position: static;
    padding-block: var(--s-3);
  }
  .journey-frame { height: clamp(120px, 34svh, 200px); }
  .journey-phases { padding-block: var(--s-5) var(--s-6); }
}

/* ---------- Reduced motion : static states, no scrubbing ---------- */
@media (prefers-reduced-motion: reduce) {
  .journey-frame video { display: none; }
  .journey-frame .journey-poster,
  .journey-frame video,
  .journey-label,
  .jt-track,
  .journey-phase { transition: none; }
  html.js .journey-phase.is-muted { opacity: 1; }
}
