/* ============================================================
   SCROLL STORY — reuses ORYZO tokens declared in :root (styles.css).
   Mostly additive; the exceptions are .hero / .story-pin / .case-detail
   below, which set up the default pin-and-cover handoff (hero stays put,
   #case-detail rises to cover it) and the .is-handoff hooks case 3's own
   pinned run needs on top of that.
   ============================================================ */

.story-pin {
  position: relative;
  /* One extra viewport height of scroll room beyond the hero's own 100vh —
     gives the sticky hero that much "hold" before it releases, exactly
     matching the distance #case-detail needs to rise from off-screen to a
     full cover (see #case-detail below). Case 3's own pinned run
     (setupPinned() in scroll-story.js) collapses this to a plain 100vh via
     inline style while armed, and the .is-armed override below restores
     normal flow for #case-detail so that run is left untouched. */
  height: 200vh;
}

.hero {
  position: sticky;
  top: 0;
  z-index: 1;
}

/* #case-detail rises from the bottom to fully cover the pinned hero above,
   driven by nothing but native scroll: pulling it up by that same 100vh
   "hold" distance means its top sits exactly at the bottom edge of the
   viewport at scrollY 0, and reaches the top of the viewport — fully
   covering the hero — right as the hero's sticky hold runs out above.
   Assumes .about (position:fixed, out of flow) and .story (empty outside
   case 3's own pinned run) contribute no flow height in between — true for
   the default hero. */
.case-detail {
  position: relative;
  z-index: 2;
  margin-top: -100vh;
  /* Softens the rising panel's leading edge as it slides up over the pinned
     hero mid-scroll — without this the hero photo gets cut by a flat, hard
     line. Same dark scrim color used throughout (rgba(16,9,4,…)) cast
     upward as a shadow instead of a gradient, so it reads as the panel
     lifting off the photo rather than a separate visual layer. */
  box-shadow: 0 -32px 56px -12px rgba(16, 9, 4, 0.4);
}

.story-pin.is-armed ~ .case-detail {
  margin-top: 0;
}

/* Hero's own static screen hands off to the pin overlay as soon as the
   user starts scrolling past the hero. (The old scroll cue that used to
   fade alongside it has been replaced by .story__progress, which is
   page-level and no longer tied to hero handoff.) */
.hero.is-handoff .hero__screen {
  opacity: 0;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

/* ---------- PIN OVERLAY (appended into .hero while armed) ---------- */

.story__pin-overlay {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease;
}

.story__pin-overlay.is-visible {
  opacity: 1;
}

/* Positioned independently — top anchored to the case-nav's vertical
   position, for the same right-column rhythm as the hero's case-nav. */
.story__panel {
  position: absolute;
  top: calc(33.08vh + 99px);
  right: 4.06vw;
  width: 15.6vw;
  min-width: 250px;
  text-align: left;
  pointer-events: none;
}

.story__panel-block {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}

.story__panel-block.is-active {
  opacity: 1;
  transform: translateY(0);
}

.story__panel-number {
  display: block;
  margin: 0 0 var(--spacing-8);
  font-size: var(--text-2xs);
  font-weight: var(--font-weight-regular);
  color: var(--text-tertiary);
}

.story__panel-kicker {
  margin: 0 0 var(--spacing-10);
  font-size: var(--outcome-label-size);
  font-weight: var(--font-weight-bold);
  line-height: 1.15;
  color: var(--color-case-accent);
}

.story__panel-heading {
  margin: 0 0 var(--spacing-10);
  font-family: var(--font-serif);
  font-size: clamp(18px, 1.6vw, 28px);
  font-weight: var(--font-weight-medium);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--text-primary);
}

.story__panel-body {
  margin: 0;
  font-size: clamp(14px, 1.05vw, 21px);
  line-height: 1.4;
  color: var(--text-secondary);
}

/* Opt-in for a heading that should read as body copy, not a display
   headline — same typeface as .story__panel-body / .story__flow-body. */
.story__panel-heading--plain,
.story__flow-heading--plain {
  font-family: var(--font-display);
  font-weight: var(--font-weight-regular);
}

.story__panel-heading--plain {
  font-size: clamp(14px, 1.05vw, 21px);
}

.story__flow-heading--plain {
  font-size: clamp(15px, 1.1vw, 20px);
}

.story__panel-list {
  margin: var(--spacing-12) 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-8);
}

.story__panel-list li {
  position: relative;
  padding-left: var(--spacing-18);
  font-size: clamp(13px, 0.95vw, 17px);
  line-height: 1.4;
  color: var(--text-secondary);
}

.story__panel-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.65em;
  width: 8px;
  height: var(--line-hairline);
  background: var(--color-case-accent);
}

/* ---------- INTRO TEASER (one-time skim-pace beat, before the first section) ---------- */

.story__teaser {
  position: absolute;
  top: calc(33.08vh + 99px);
  right: 4.06vw;
  width: 15.6vw;
  min-width: 250px;
  text-align: left;
  pointer-events: none;
}

.story__teaser-line {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.35s ease, transform 0.35s ease;
  font-family: var(--font-display);
  font-size: clamp(16px, 1.4vw, 26px);
  font-weight: var(--font-weight-medium);
  line-height: 1.3;
  color: var(--text-primary);
}

.story__teaser-line.is-active {
  opacity: 1;
  transform: translateY(0);
}

.story__quote {
  margin: var(--spacing-12) 0 0;
  padding-left: var(--spacing-18);
  border-left: var(--line-accent) solid var(--color-case-accent);
  font-family: var(--font-serif);
  font-size: clamp(16px, 1.3vw, 22px);
  font-style: normal;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--text-secondary);
}

/* Same markup also lands inside the flow sections and their stacked/mobile
   equivalent, which sit on the story's own (light) background rather than
   over the pinned hero photo — so the quote needs the dark ink there. */
.story__flow-section .story__quote,
.story__mobile-block .story__quote {
  color: var(--color-cork-border);
}

/* Screen overlay — positioned via LaptopMockup.computeScreenRect() to sit
   exactly over the hero's laptop screen. */
.story__screen {
  position: absolute;
  z-index: 2;
  overflow: hidden;
  background: #e4e4e0;
}

.story__screen-video {
  /* Overscanned 1px past the container on every side, then clipped back by
     the container's overflow:hidden — hides the sub-pixel seam that shows
     the laptop photo behind at the container's fractional (non-integer px)
     position. */
  position: absolute;
  left: -1px;
  top: -1px;
  width: calc(100% + 2px);
  height: calc(100% + 2px);
  object-fit: cover;
  border-radius: inherit;
}

/* ---------- PROGRESS TRAIL (rotated-line language, no section names) ---------- */

.story__progress {
  position: fixed;
  right: var(--spacing-48);
  /* top/height are set from JS (positionTrail() in scroll-story.js), which
     bottom-aligns this to the hero case description text and height-matches
     it to the left-side .case-nav rail — bottom/height here are only the
     pre-JS fallback for the first paint. No min-height: it would win over
     the JS-computed height whenever .case-nav is shorter than that floor,
     breaking the height-match this element exists to keep. */
  bottom: 5.45vh;
  height: 34vh;
  z-index: 20;
  opacity: 0;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

.story__progress.is-visible {
  opacity: 1;
}

/* The About overlay sits above this trail (z-index 10 vs. 20), so without
   this the line/marker/hint would float on top of it. */
body.about-open .story__progress {
  opacity: 0;
  pointer-events: none;
}

/* "Back to top" indicator — takes over .story__progress-hint's exact spot
   (same bottom:4px anchor, same --rail-label-gap offset) once the landing
   hero is fully covered by the case study (hero-covered), rather than
   hiding hint fade like the first scroll tick does. Reads as a replacement
   for the hint, not a separate element: the label sits where "Scroll down
   to case study" sat, with just the caret added above it. */
.story__progress-top {
  position: absolute;
  bottom: 4px;
  /* .story__progress sits at right: var(--spacing-48), so subtracting
     that back out lands this label's own right edge at exactly
     --rail-label-gap from the viewport edge — mirrors .case-nav__label's
     calc() in styles.css on the left rail. */
  right: calc(var(--rail-label-gap) - var(--spacing-48));
  display: block;
  background: none;
  border: none;
  padding: 0;
  color: var(--color-grey);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease, color 0.4s ease;
}

.story__progress.hero-covered .story__progress-top {
  opacity: 1;
  pointer-events: auto;
}

.story__progress-top:hover {
  opacity: 0.65;
}

.story__progress-top-icon {
  position: absolute;
  bottom: 100%;
  left: 50%;
  margin-bottom: var(--spacing-6);
  margin-left: -3.5px;
  width: 7px;
  height: 7px;
  border-top: var(--line-hairline) solid currentColor;
  border-right: var(--line-hairline) solid currentColor;
  transform: rotate(-45deg);
}

.story__progress-top-label {
  display: block;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: nowrap;
  font-size: var(--text-2xs);
  font-weight: var(--font-weight-regular);
}

.story__progress.is-on-light .story__progress-top {
  color: var(--color-grey);
}

/* Fixed-length track — same position and length at every scroll position,
   from the top of the hero through the end of #case-detail. Never resized
   or repositioned; only .story__progress-marker below moves. */
.story__progress-line {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--line-hairline);
  background: rgba(255, 255, 255, 0.6);
  transition: opacity 0.3s ease;
}

/* Traveled portion of the track, drawn in red. Grows via scaleY(frac) from
   a fixed top origin rather than a background-gradient stop, and shares the
   marker's own "transform 0.5s ease" below verbatim — a gradient stop
   updates instantly with no way to transition it, which let the fill race
   ahead of the marker it's meant to trail exactly. Same transition on the
   same CSS property (transform) is what keeps the two in lockstep. */
.story__progress-fill {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--line-hairline);
  height: 100%;
  background: var(--color-brand-red);
  transform-origin: top;
  transform: scaleY(0);
  transition: transform 0.5s ease;
}

/* The only moving part: translateY is set from JS as frac * track height
   (plus the -50% self-centering below), so it travels smoothly along the
   fixed-length track above instead of the track itself changing size. */
.story__progress-marker {
  position: absolute;
  top: 0;
  left: -3px;
  width: 7px;
  height: 7px;
  background: var(--color-brand-red);
  transform: translateY(-50%);
  transition: transform 0.5s ease, background 0.4s ease, opacity 0.3s ease;
}

/* Once the footer has scrolled into view, the line/marker's job (tracking
   progress through the still-scrolling middle of the page) is done — drop
   them so a long line doesn't visually run through the footer band, while
   the vertical "Back to top" label (governed separately by hero-covered)
   keeps reading at the very bottom of the page. */
.story__progress.at-page-end .story__progress-line,
.story__progress.at-page-end .story__progress-fill,
.story__progress.at-page-end .story__progress-marker {
  opacity: 0;
}

/* Standalone wayfinding hint, decoupled from any line element (replaces
   the old .scroll-cue__text, which was anchored to a now-removed line).
   Anchored near the bottom of the trail's own fixed box — same bottom:4px
   inset the old .scroll-cue__text used, which now lines up again since
   the box itself is bottom-anchored to the same offset the old .scroll-cue
   box used. Fades out on the first scroll tick on any case, not just
   case 3's pin handoff. */
.story__progress-hint {
  position: absolute;
  bottom: 4px;
  /* Mirrors .case-nav__label's calc() on the left rail — see
     .story__progress-top above. */
  right: calc(var(--rail-label-gap) - var(--spacing-48));
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: nowrap;
  font-size: var(--text-2xs);
  font-weight: var(--font-weight-regular);
  color: var(--text-tertiary);
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
  opacity: 1;
  transition: opacity 0.4s ease;
}

.story__progress.has-scrolled .story__progress-hint {
  opacity: 0;
}

/* Once the pin releases and the page behind the rail turns from the dark
   hero photo to the story section's light background, the off-white line
   and marker would vanish right as they reach the end — swap to dark ink. */
.story__progress.is-on-light .story__progress-line {
  background: var(--color-image-stroke);
}

/* Small contextual caption ("01 — Context") beside a heading — fades with
   the section it belongs to, never lives in a fixed sidebar. */
.story__caption {
  display: inline-block;
  margin: 0 0 var(--spacing-10);
  font-size: var(--text-2xs);
  font-weight: var(--font-weight-regular);
  color: var(--color-brand-red);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.4s ease, transform 0.4s ease;
}

.story__flow-section.is-visible .story__caption,
.story__mobile-block.is-visible .story__caption {
  opacity: 1;
  transform: translateY(0);
}

/* ---------- FLOW SECTIONS (closing cue) — normal document scroll, after the pinned run ---------- */

.story {
  position: relative;
  background: var(--color-off-white);
}

.story__flow-section {
  min-height: 70vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--spacing-12);
  padding: var(--spacing-68) var(--spacing-48);
  max-width: 720px;
  margin: 0 auto;
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.story__flow-section.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.story__flow-heading {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(28px, 3.2vw, 48px);
  line-height: 1.05;
  letter-spacing: -0.01em;
  color: var(--color-walnut-shadow);
}

.story__flow-body {
  margin: 0;
  max-width: 60ch;
  font-size: clamp(15px, 1.1vw, 20px);
  line-height: 1.5;
  color: var(--color-cork-border);
}

.story__stat-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-24);
  margin: var(--spacing-12) 0 0;
  padding: 0;
  list-style: none;
}

.story__stat-list li {
  flex: 1 1 200px;
  border-top: var(--line-hairline) solid var(--color-cork-border);
  padding-top: var(--spacing-12);
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--color-cork-border);
}

/* Closing cue — same rotated-label + vertical-line pattern as the hero's
   "Scroll down to case study" cue. */
.story__closing {
  display: flex;
  justify-content: flex-end;
  padding: 0 var(--spacing-48) var(--spacing-68);
}

.story__closing-cue {
  position: relative;
  display: block;
  /* Same length as .story__progress, so the two rails read as one
     consistent scroll-line language across the case study. */
  height: 34vh;
  min-height: 220px;
  padding-left: 20px;
  color: rgba(16, 9, 4, 0.4);
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.story__closing-cue.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.story__closing-cue::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--line-hairline);
  background: rgba(16, 9, 4, 0.35);
}

.story__closing-cue-text {
  position: absolute;
  left: 10px;
  bottom: 4px;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: nowrap;
  font-size: var(--text-2xs);
  color: var(--color-walnut-shadow);
}

/* ---------- STACKED LAYOUT (mobile, and reduced-motion fallback) ---------- */

.story__mobile-block {
  padding: var(--spacing-48) var(--spacing-24);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-12);
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}

.story__mobile-block.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.story__mobile-laptop {
  position: relative;
  width: 100%;
  margin-bottom: var(--spacing-12);
}

/* The site's name/role + ABOUT nav are position:fixed above everything
   (styles.css .intro / .side-nav, z-index 11) and stay legible over the
   hero only because .hero__vignette permanently darkens it underneath.
   Stacked story blocks have no such backing, so a light laptop photo
   scrolling to the top of the viewport washes that text out — this
   reproduces the same top-edge scrim locally, just for these thumbnails. */
.story__mobile-laptop::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 110px;
  background: linear-gradient(to bottom, rgba(16, 9, 4, 0.55), rgba(16, 9, 4, 0));
  pointer-events: none;
  z-index: 1;
}

.story__mobile-laptop-photo {
  display: block;
  width: 100%;
  height: auto;
}

.story__mobile-laptop-screen {
  position: absolute;
  object-fit: cover;
}

/* Stacked teaser block — same laptop + screenshot treatment as a full
   section, but only the one-line placeholder instead of heading/body. */
.story__mobile-teaser {
  padding: var(--spacing-48) var(--spacing-24) var(--spacing-24);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-8);
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}

.story__mobile-teaser.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.story__teaser-line--mobile {
  position: static;
  transform: none;
  opacity: 1;
  transition: none;
  font-size: clamp(16px, 4.5vw, 20px);
  color: var(--color-walnut-shadow);
}

/* No-motion mode (prefers-reduced-motion): everything is simply visible,
   with no scroll-linked animation. */
.story.no-motion .story__mobile-block,
.story.no-motion .story__mobile-teaser,
.story.no-motion .story__flow-section,
.story.no-motion .story__closing-cue,
.story.no-motion .story__caption {
  opacity: 1 !important;
  transform: none !important;
  transition: none !important;
}

/* ---------- REDUCED MOTION ---------- */

@media (prefers-reduced-motion: reduce) {
  .hero {
    position: relative !important;
  }
  .story-pin {
    height: auto !important;
  }
  .case-detail {
    margin-top: 0 !important;
    box-shadow: none !important;
  }
  .story__pin-overlay,
  .story__panel-block,
  .story__teaser-line {
    transition: none !important;
  }
  .story__progress {
    display: none;
  }
}

/* ---------- MOBILE (matches the hero's own 980px breakpoint) ---------- */

@media (max-width: 980px) {
  /* Pin-and-cover reveal is a desktop-scroll effect — plain stacked flow
     on mobile, same as the case-3 pin overlay it sits alongside below. */
  .story-pin {
    height: auto;
  }
  .hero {
    position: relative;
  }
  .case-detail {
    margin-top: 0;
    box-shadow: none;
  }
  .story__pin-overlay {
    display: none;
  }
  .story__progress {
    display: none;
  }
  .story__flow-section {
    padding: var(--spacing-48) var(--spacing-24);
    max-width: none;
  }
  .story__closing {
    padding: 0 var(--spacing-24) var(--spacing-48);
    justify-content: flex-start;
  }
}
