/* The scrollytelling hero.
 *
 * A tall scroller with a sticky 100vh stage. Inside it, the scene lives on a
 * dark card and the generated program on a second, taller card that overlaps
 * the scene's right edge. Copy sits on the page around them, so nothing needs a
 * scrim and there are no gradients anywhere.
 *
 * Scroll progress drives five beats: arrival -> code -> segmentation -> point
 * cloud -> abstraction -> simulation. Beat state is written from JS as CSS
 * custom properties, so the whole sequence scrubs in both directions.
 */

.vda-hero {
  position: relative;
  background: var(--vda-bg);
}

/* Longer than the visual sequence needs, because a third of it is dwell
   (see DWELL in hero/index.js) and the transitions should not speed up. */
.vda-hero__scroller {
  height: 900vh;
}

.vda-hero__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  align-content: center;
  gap: clamp(16px, 2.4vh, 30px);
  max-width: var(--vda-content);
  margin: 0 auto;
  padding: clamp(18px, 3vh, 34px) 32px;
}

/* Masthead ------------------------------------------------------------------ */
/* Collapses to a compact single line once the sequence starts, so the cards
   get the vertical room. */

.vda-hero__masthead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}

.vda-hero__masthead .vda-display {
  font-size: clamp(2rem, calc(2rem + var(--mast-open, 1) * 3.2vw), 5.2rem);
  transition: font-size var(--vda-slow) var(--vda-ease);
}

.vda-hero__lede {
  max-width: 30ch;
  color: var(--vda-fg);
  font-weight: 450;
  opacity: var(--lede-opacity, 1);
  transition: opacity 180ms var(--vda-ease);
}

.vda-hero__byline {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: flex-end;
  text-align: right;
  opacity: var(--mast-open, 1);
  transition: opacity var(--vda-base) var(--vda-ease);
}

/* Card composition ---------------------------------------------------------- */

.vda-hero__cards {
  position: relative;
  align-self: center;
  width: 100%;
}

/* Arrival shows input and result side by side; as the sequence starts the
   result card leaves and the scene takes the width back. --result-open is
   driven from the scroll driver, so the two are always consistent. */
.vda-hero__scene {
  position: relative;
  width: calc(min(74%, 860px) - var(--result-open, 0) * min(26%, 300px));
  aspect-ratio: 16 / 9;
  border-radius: var(--vda-radius);
  overflow: hidden;
  background: var(--vda-card);
  border: 1px solid var(--vda-card-border);
  box-shadow: 0 1px 2px rgba(16, 16, 20, 0.06), 0 12px 34px rgba(16, 16, 20, 0.09);
}

.vda-hero__photo,
.vda-hero__canvas,
.vda-hero__masks {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.vda-hero__photo {
  object-fit: cover;
  /* Sits above the canvas for the cross-dissolve, so it must not swallow the
     pointer once it has faded out — that is what broke orbiting. */
  pointer-events: none;
  opacity: var(--photo-opacity, 1);
  transform: scale(calc(1 + var(--photo-zoom, 0) * 0.03));
  will-change: opacity, transform;
}

.vda-hero__canvas {
  display: block;
  opacity: var(--canvas-opacity, 0);
  pointer-events: none;
}

.vda-hero.is-interactive .vda-hero__canvas {
  pointer-events: auto;
  cursor: grab;
}

.vda-hero.is-interactive .vda-hero__canvas:active {
  cursor: grabbing;
}

/* Mask overlay (SAM 3) ------------------------------------------------------ */

.vda-hero__masks {
  pointer-events: none;
  opacity: var(--masks-opacity, 0);
}

.vda-hero__masks path {
  fill: var(--mask-fill);
  fill-opacity: calc(var(--mask-reveal, 0) * 0.26);
  stroke: var(--mask-stroke);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: var(--mask-len);
  stroke-dashoffset: calc(var(--mask-len) * (1 - var(--mask-reveal, 0)));
}

/* Result card --------------------------------------------------------------- */

.vda-hero__result {
  position: absolute;
  right: 0;
  top: 0;
  width: min(48%, 560px);
  margin: 0;
  opacity: var(--result-open, 1);
  transform: translateX(calc((1 - var(--result-open, 1)) * 18px));
  transition: opacity var(--vda-base) var(--vda-ease),
    transform var(--vda-base) var(--vda-ease);
  /* Only clickable while it is actually on screen — once faded out it must not
     keep intercepting pointer events over the scene beneath it. */
  pointer-events: none;
}

.vda-hero.is-arrival .vda-hero__result {
  pointer-events: auto;
}

.vda-hero__result video {
  width: 100%;
  display: block;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--vda-radius);
  background: var(--vda-card);
  border: 1px solid var(--vda-card-border);
  box-shadow: 0 1px 2px rgba(16, 16, 20, 0.06), 0 12px 34px rgba(16, 16, 20, 0.09);
}

.vda-hero__result figcaption {
  margin-top: 10px;
  font-size: 0.82rem;
  color: var(--vda-muted);
}

.vda-hero__result figcaption b {
  color: var(--vda-accent);
  font-weight: 600;
}

/* Code card ----------------------------------------------------------------- */
/* Taller than the scene card and offset to the right, clipping its corner just
   enough to read as a layered stack rather than a two-column grid. */

.vda-hero__code {
  position: absolute;
  right: 0;
  top: -7%;
  height: 114%;
  width: min(42%, 470px);
  display: flex;
  flex-direction: column;
  border-radius: var(--vda-radius);
  overflow: hidden;
  background: var(--vda-card);
  border: 1px solid var(--vda-card-border);
  box-shadow: 0 2px 6px rgba(16, 16, 20, 0.08), 0 20px 50px rgba(16, 16, 20, 0.16);
  color: var(--vda-on-card);
  opacity: var(--code-opacity, 0);
  transform: translateX(calc((1 - var(--code-opacity, 0)) * 28px));
  transition: transform var(--vda-base) var(--vda-ease);
  pointer-events: none;
}

.vda-hero__code-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--vda-card-border);
  background: var(--vda-card-2);
  color: var(--vda-on-card-faint);
  font-family: var(--vda-mono);
  font-size: 0.72rem;
  flex: none;
}

.vda-hero__code-dots {
  display: flex;
  gap: 6px;
}

.vda-hero__code-dots i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.16);
}

.vda-hero__code-scroll {
  flex: 1;
  overflow: hidden;
  position: relative;
  /* Fade at both ends so the panel reads as a viewport onto a longer file. */
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 7%, #000 90%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 7%, #000 90%, transparent);
}

/* Bulma styles bare <pre> with a whitesmoke background and dark text, which
   turned the whole panel light and left the highlighted line near-white on pale
   blue. Reset explicitly rather than relying on the card behind it. */
.vda-hero__code pre,
.vda-hero__code code {
  background: transparent;
  background-color: transparent;
  color: var(--vda-on-card);
  border-radius: 0;
  overflow: visible;
  word-wrap: normal;
}

.vda-hero__code pre {
  margin: 0;
  padding: 18px 0;
  transform: translateY(var(--code-scroll, 0px));
  transition: transform var(--vda-slow) var(--vda-ease);
  font-family: var(--vda-mono);
  font-size: 0.72rem;
  line-height: 1.72;
  tab-size: 4;
}

.vda-hero__code .ln {
  display: block;
  padding: 0 16px;
  color: #868c9a;
  white-space: pre;
  opacity: 0;
  transform: translateY(3px);
  transition: opacity var(--vda-base) var(--vda-ease),
    transform var(--vda-base) var(--vda-ease),
    background var(--vda-base) var(--vda-ease);
}

.vda-hero__code .ln.is-typed {
  opacity: 1;
  transform: none;
}

/* The API call the current beat is illustrating. Every token brightens, not
   just the line's own colour, or the syntax stays unreadable on the wash. */
.vda-hero__code .ln.is-active {
  background: rgba(76, 157, 255, 0.2);
  box-shadow: inset 2px 0 0 var(--vda-accent-on-card);
  color: #eef2f7;
}

.vda-hero__code .ln.is-active .tok-kw { color: #dcb8ff; }
.vda-hero__code .ln.is-active .tok-str { color: #a5e8b4; }
.vda-hero__code .ln.is-active .tok-num { color: #ffc48c; }
.vda-hero__code .ln.is-active .tok-com { color: #8b93a3; }
.vda-hero__code .ln.is-active .tok-api { color: #8fd4ff; }
.vda-hero__code .ln.is-active .tok-def { color: #ffe3a3; }

.vda-hero__code .tok-kw { color: #b184e8; }
.vda-hero__code .tok-str { color: #6fbe86; }
.vda-hero__code .tok-num { color: #d99358; }
.vda-hero__code .tok-com { color: #565b68; font-style: italic; }
.vda-hero__code .tok-api { color: #4c9dff; font-weight: 600; }
.vda-hero__code .tok-def { color: #e0bd72; }

/* Footer row ---------------------------------------------------------------- */

.vda-hero__foot {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 20px 24px;
  min-height: clamp(96px, 15vh, 150px);
}

/* The input caption and the beat captions occupy the same cell: the caption
   holds the space on arrival and hands over as the sequence starts. */
.vda-hero__narrative {
  display: grid;
  grid-template-areas: "narrative";
  align-items: end;
  min-width: 0;
}

.vda-hero__narrative > * {
  grid-area: narrative;
  min-width: 0;
}

.vda-hero__beat {
  max-width: 52ch;
  opacity: var(--beat-opacity, 0);
  transform: translateY(calc((1 - var(--beat-opacity, 0)) * 8px));
  /* Smooths the one-frame drop when a beat hands over to the next. */
  transition: opacity 180ms var(--vda-ease);
}

.vda-hero__beat h2 {
  font-size: clamp(1.25rem, 2.1vw, 1.75rem);
  font-weight: 640;
  letter-spacing: -0.028em;
  line-height: 1.15;
  margin: 8px 0 0;
  color: var(--vda-fg);
}

.vda-hero__beat p {
  margin: 7px 0 0;
  color: var(--vda-muted);
  font-size: 0.94rem;
  line-height: 1.5;
}

.vda-hero__beat .vda-tool {
  color: var(--vda-accent);
  font-weight: 550;
}

/* The input caption, overlaid on the photograph: it belongs to the image, and
   putting it there frees the footer for the lede and the navigation. */
.vda-hero__caption {
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 16px;
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0;
  padding: 10px 14px;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(8, 8, 10, 0.62);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  color: rgba(255, 255, 255, 0.82);
  font-family: var(--vda-mono);
  font-size: 0.74rem;
  line-height: 1.45;
  max-width: 52ch;
  opacity: var(--caption-opacity, 1);
  pointer-events: none;
}

.vda-hero__caption b {
  color: rgba(255, 255, 255, 0.45);
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-size: 0.64rem;
  flex: none;
}

/* Simulation controls -------------------------------------------------------- */

.vda-hero__sim {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: flex-start;
  opacity: var(--sim-opacity, 0);
  pointer-events: none;
  grid-column: 1 / -1;
}

.vda-hero.is-interactive .vda-hero__sim {
  pointer-events: auto;
}

.vda-hero__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

.vda-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid var(--vda-border);
  background: transparent;
  color: var(--vda-muted);
  font-family: var(--vda-sans);
  font-size: 0.84rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--vda-fast) var(--vda-ease),
    border-color var(--vda-fast) var(--vda-ease),
    background var(--vda-fast) var(--vda-ease);
}

.vda-chip:hover {
  color: var(--vda-fg);
  border-color: var(--vda-border-strong);
}

.vda-chip[aria-pressed="true"] {
  color: var(--vda-bg);
  background: var(--vda-fg);
  border-color: var(--vda-fg);
}

/* Outcome dot: green when the tower survives the edit, amber when it falls. */
.vda-chip__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--vda-warn);
}

.vda-chip[data-outcome="stands"] .vda-chip__dot {
  background: var(--vda-ok);
}

.vda-chip[aria-pressed="true"] .vda-chip__dot {
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.22);
}

.vda-hero__transport {
  display: flex;
  align-items: center;
  gap: 12px;
  width: min(100%, 460px);
}

.vda-hero__play {
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 50%;
  border: 1px solid var(--vda-border-strong);
  background: transparent;
  color: var(--vda-fg);
  cursor: pointer;
  display: grid;
  place-items: center;
  font-size: 0.72rem;
  line-height: 1;
}

.vda-hero__play:hover {
  border-color: var(--vda-accent);
  color: var(--vda-accent);
}

.vda-hero__scrub {
  flex: 1;
  appearance: none;
  -webkit-appearance: none;
  height: 3px;
  border-radius: 999px;
  background: var(--vda-border);
  cursor: pointer;
}

.vda-hero__scrub::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--vda-fg);
  border: none;
}

.vda-hero__scrub::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: none;
  border-radius: 50%;
  background: var(--vda-fg);
}

.vda-hero__clock {
  font-family: var(--vda-mono);
  font-size: 0.72rem;
  color: var(--vda-faint);
  min-width: 4.5ch;
}

.vda-hero__blurb {
  color: var(--vda-muted);
  font-size: 0.9rem;
  max-width: 56ch;
  margin: 0;
}

/* The diff that produced the selected world. */
.vda-hero__diff {
  border: 1px solid var(--vda-border);
  border-radius: 10px;
  background: var(--vda-bg-sunken);
  max-width: 560px;
  overflow: hidden;
}

.vda-hero__diff summary {
  padding: 9px 14px;
  cursor: pointer;
  color: var(--vda-muted);
  font-family: var(--vda-mono);
  font-size: 0.74rem;
  list-style: none;
}

.vda-hero__diff summary::-webkit-details-marker {
  display: none;
}

.vda-hero__diff[open] summary {
  border-bottom: 1px solid var(--vda-border);
  color: var(--vda-fg);
}

.vda-hero__diff pre {
  margin: 0;
  padding: 12px 14px;
  font-family: var(--vda-mono);
  font-size: 0.72rem;
  line-height: 1.6;
  color: var(--vda-muted);
  overflow-x: auto;
  white-space: pre;
}

.vda-hero__diff .add { color: #1f7a44; }
.vda-hero__diff .del { color: #b03636; }

/* Navigation and progress rail ------------------------------------------------ */
/* Two buttons, deliberately unequal: stepping through the sequence is the
   intended path, so it is the filled one. Leaving is available but quieter. */

.vda-hero__nav {
  display: flex;
  align-items: center;
  gap: 10px;
  align-self: end;
}

.vda-hero__next span {
  display: inline-block;
  animation: vda-nudge 2.4s var(--vda-ease) infinite;
}

.vda-hero__next[hidden] {
  display: none;
}

.vda-hero__skip {
  color: var(--vda-muted);
  white-space: nowrap;
}

.vda-hero__skip:hover {
  color: var(--vda-fg);
}

@keyframes vda-nudge {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(3px); }
}

/* Outside the cards, in the page margin: sitting inside the composition it
   landed on the code card, whose styling it disappeared into. */
.vda-hero__rail {
  position: absolute;
  left: -24px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 8px;
  opacity: var(--rail-opacity, 0);
}

.vda-hero__rail button {
  width: 7px;
  height: 7px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--vda-border-strong);
  cursor: pointer;
  transition: background var(--vda-base) var(--vda-ease),
    transform var(--vda-base) var(--vda-ease);
}

.vda-hero__rail button:hover {
  background: var(--vda-muted);
  transform: scale(1.4);
}

.vda-hero__rail button.is-on {
  background: var(--vda-accent);
  transform: scale(1.5);
}

.vda-hero__rail button:focus-visible {
  outline: 2px solid var(--vda-accent);
  outline-offset: 3px;
}

/* Static fallback ------------------------------------------------------------ */
/* Reduced motion, narrow viewports and missing WebGL all land here: nothing is
   pinned, the cards unstack into normal flow, and the live scene is replaced by
   the MuJoCo render of the same rollout. The chips stay live in both modes, so
   there is only ever one set of controls in the DOM. */

.vda-hero__fallback {
  display: none;
}

.vda-hero.is-static .vda-hero__scroller {
  height: auto;
}

.vda-hero.is-static .vda-hero__stage {
  position: relative;
  height: auto;
  display: block;
  padding-top: clamp(40px, 8vh, 80px);
  padding-bottom: clamp(40px, 8vh, 80px);
}

.vda-hero.is-static .vda-hero__canvas,
.vda-hero.is-static .vda-hero__rail,
.vda-hero.is-static .vda-hero__result,
.vda-hero.is-static .vda-hero__next {
  display: none;
}

.vda-hero.is-static .vda-hero__scene,
.vda-hero.is-static .vda-hero__code {
  position: relative;
  inset: auto;
  width: 100%;
  height: auto;
  top: auto;
  opacity: 1;
  transform: none;
  margin-bottom: 20px;
}

.vda-hero.is-static .vda-hero__code {
  height: min(60svh, 480px);
}

.vda-hero.is-static .vda-hero__masks {
  opacity: 1;
}

.vda-hero.is-static .vda-hero__beat,
.vda-hero.is-static .vda-hero__sim {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.vda-hero.is-static .vda-hero__foot {
  display: block;
}

.vda-hero.is-static .vda-hero__sim {
  margin-top: 24px;
}

.vda-hero.is-static .vda-hero__fallback {
  display: block;
  margin-bottom: 16px;
}

.vda-hero__fallback video {
  width: 100%;
  display: block;
  border-radius: var(--vda-radius);
  border: 1px solid var(--vda-card-border);
  background: var(--vda-card);
}

/* Narrow ---------------------------------------------------------------------- */

@media (max-width: 1080px) {
  .vda-hero__scene {
    width: 100%;
  }

  .vda-hero__rail {
    left: -20px;
  }

  /* The code card is supporting material, not load-bearing: the beat captions
     already say what the program is doing. Below this width the overlap costs
     more of the scene than the panel is worth, so it goes. */
  .vda-hero__code,
  .vda-hero__result {
    display: none;
  }

  .vda-hero__scene {
    width: 100%;
  }

  /* Below this the overlap steals too much of the scene, so the code card
     becomes an inset panel over the card's lower half instead. */
  .vda-hero__code {
    top: auto;
    bottom: 8px;
    right: 8px;
    height: 62%;
    width: min(52%, 400px);
  }
}

@media (max-width: 820px) {
  .vda-hero__masthead {
    flex-direction: column;
    align-items: flex-start;
  }

  .vda-hero__byline {
    align-items: flex-start;
    text-align: left;
  }

  .vda-hero__foot {
    grid-template-columns: 1fr;
  }
}
