/* IAMX story: the dark stage, the pinned scroll and the slot. Every value is a token from tokens.css.
   Base rules are the plain page, for no JavaScript or no WebGL2: a normal-height dark hero, then the Services band.
   .scene is the scroll story (set before first paint in index.html), .still is the reduced-motion single frame. */

/* Base: the plain dark hero */
.story {
  position: relative;
  background: var(--stage-bg);
  color: var(--stage-text);
}
.stage { position: relative; background: var(--stage-bg); }
.stage-canvas, .stage-shade, .stage-veil, .slot { display: none; }

.stage-copy {
  max-width: calc(var(--content-max) + 2 * var(--grid-margin));
  margin-inline: auto;
  padding: var(--space-9) var(--grid-margin);
}
.hero-copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-6);
}
.display {
  font-size: var(--step-display);
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
  font-weight: var(--weight-bold);
}
.hero-lead {
  max-width: var(--measure);
  font-size: var(--step-lead);
  line-height: var(--lh-lead);
  letter-spacing: var(--track-lead);
  font-weight: var(--weight-medium);
  text-wrap: pretty;
}
.hero-cta { padding-top: var(--space-2); }
.mask, .mask-in { display: block; }

/* The stage always uses the dark set, whatever the page theme */
.story .x { color: var(--stage-accent); }
.stage .button { background: var(--stage-accent); color: var(--stage-on-accent); }
.stage .button:hover { background: var(--stage-accent-hover); color: var(--stage-on-accent); }
.stage .button:active { background: var(--stage-accent); color: var(--stage-on-accent); }
.stage :focus-visible { outline-color: var(--stage-focus); }

/* The header over the stage: transparent, in the stage's colours. scripts/hero.js sets data-on-stage. */
.site-header {
  transition:
    border-color var(--dur-header) var(--ease-standard),
    background-color var(--dur-header) var(--ease-standard);
}
.site-header[data-on-stage] { background: transparent; border-bottom-color: transparent; }
.site-header[data-on-stage="solid"] { background: var(--stage-bg); }
.site-header[data-on-stage] .mark,
.site-header[data-on-stage] .mark:hover,
.site-header[data-on-stage] .nav a { color: var(--stage-text); }
.site-header[data-on-stage] .mark .x { color: var(--stage-accent); }
.site-header[data-on-stage] .nav a:hover { color: var(--stage-accent-hover); }
.site-header[data-on-stage] .button { background: var(--stage-accent); color: var(--stage-on-accent); }
.site-header[data-on-stage] .button:hover { background: var(--stage-accent-hover); color: var(--stage-on-accent); }
.site-header[data-on-stage] :focus-visible { outline-color: var(--stage-focus); }

/* The header's own "Tell us your X" steps aside while the hero's copy of it is on screen, so the first screen carries
   one button, not two. scripts/hero.js sets data-cta-away; without it (no JavaScript) the header keeps its button. */
.header-actions > .button {
  transition:
    background-color var(--dur-fast) var(--ease-standard),
    opacity var(--dur-base) var(--ease-enter),
    visibility 0s linear 0s;
}
.site-header[data-cta-away] .header-actions > .button {
  opacity: 0;
  visibility: hidden;
  transition:
    background-color var(--dur-fast) var(--ease-standard),
    opacity var(--dur-base) var(--ease-exit),
    visibility 0s linear var(--dur-base);
}

/* Scene and still: a full-viewport stage with the canvas behind the copy */
.scene .story, .still .story { margin-top: calc(-1 * var(--header-h)); }
.scene .stage, .still .stage { height: 100svh; overflow: hidden; }
.scene .stage-canvas, .still .stage-canvas {
  display: block;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.scene .stage-shade, .still .stage-shade {
  display: block;
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* Top for the header and left for the words. The side fade ends just past the words' column, so it never dims
     the X, which the scene always frames clear of the words. */
  background:
    linear-gradient(to bottom, var(--stage-scrim), var(--stage-scrim-0) var(--scrim-top-h)),
    linear-gradient(to right, var(--stage-scrim-mid), var(--stage-scrim-0) var(--scrim-side-w));
}
/* The foot: the floor goes to the stage's own dark only as the stage leaves (scripts/hero.js sets --foot), so the
   stage leaves on a clean edge and nothing lies over the cropped X while the stage is held. */
.scene .stage-shade::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, var(--stage-bg), var(--stage-scrim-0) var(--scrim-foot-h));
  opacity: var(--foot, 0);
}
.scene .stage-copy, .still .stage-copy {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: var(--stage-copy-w) minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  padding: var(--header-h) var(--grid-margin) var(--stage-pad-bottom);
  pointer-events: none;
}
.scene .hero-copy, .still .hero-copy {
  grid-area: 1 / 1;
  align-self: center;
  pointer-events: auto;
}
.scene .hero-lead, .still .hero-lead { max-width: none; }

/* Scene only: the stage pins over six stops and a release */
html.scene { scroll-behavior: auto; }
.scene .stage { position: sticky; top: 0; }
.scene .story-track {
  position: relative;
  height: calc(var(--slot-scroll-per-stop) * var(--slot-stops));
}
/* The tail is the stage's own height: the stage lets go exactly as the sixth stop ends, and scrolls away. */
.scene .story-tail { height: 100svh; }
/* The list stays for screen readers and is where the Services link lands: halfway into stop one */
.scene .services {
  position: absolute;
  top: calc(0.5 * var(--slot-scroll-per-stop));
  left: 0;
  width: var(--sr-size);
  height: var(--sr-size);
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.scene .services * { white-space: nowrap; }
.scene .stage-veil {
  display: block;
  position: absolute;
  inset: 0;
  background: var(--bg);
  opacity: 0;
  pointer-events: none;
}

/* The load reveal: masked lines, gated on the first rendered frame (is-ready), at most 1.4 s in all */
.scene .hero-copy .mask {
  overflow: hidden;
  padding: var(--mask-pad-y) var(--mask-pad-x) var(--mask-pad-y) 0;
  margin: calc(-1 * var(--mask-pad-y)) calc(-1 * var(--mask-pad-x)) calc(-1 * var(--mask-pad-y)) 0;
}
.scene .hero-copy .mask-in { transform: translateY(var(--mask-travel)); }
.scene .hero-cta { opacity: 0; }
.scene.is-ready .hero-copy .mask-in {
  transform: none;
  transition: transform var(--dur-reveal) var(--ease-enter) var(--reveal-delay-1);
}
.scene.is-ready .hero-lead .mask-in { transition-delay: var(--reveal-delay-2); }
.scene.is-ready .hero-cta {
  opacity: 1;
  transition: opacity var(--dur-reveal) var(--ease-enter) var(--reveal-delay-3);
}

/* The slot: rail, "I am", then one unit per stop, stacked in one cell. Its top never moves. */
.scene .slot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  grid-area: 1 / 1;
  align-self: start;
  margin-top: calc(var(--slot-top) - var(--header-h));
}
.rail {
  display: flex;
  gap: var(--rail-gap);
  margin-bottom: var(--space-5);
  opacity: 0;
  transition: opacity var(--dur-slot) var(--ease-exit);
}
.slot.is-on .rail { opacity: 1; transition-timing-function: var(--ease-enter); }
.rail li {
  width: var(--rail-mark-w);
  height: var(--rail-mark-h);
  background: var(--stage-muted);
  transition:
    width var(--dur-slot) var(--ease-standard),
    background-color var(--dur-slot) var(--ease-standard);
}
.rail li.is-on { width: var(--rail-mark-on-w); background: var(--stage-accent); }

.slot { text-shadow: var(--stage-text-halo); }
.slot-lead, .slot-label {
  font-size: var(--step-slot);
  line-height: var(--lh-slot);
  letter-spacing: var(--track-slot);
  font-weight: var(--weight-bold);
}
.slot-label { font-style: italic; color: var(--stage-accent); text-wrap: balance; }
.slot-units { display: grid; width: 100%; }
/* A unit off stage is hidden once its exit has run, so no overhang or descender can show below its mask */
.slot-unit {
  grid-area: 1 / 1;
  align-self: start;
  visibility: hidden;
  transition: visibility 0s linear var(--dur-slot);
}
.slot-unit.is-active { visibility: visible; transition-delay: 0s; }
.slot-line {
  margin-top: var(--space-5);
  max-width: var(--measure);
  font-size: var(--step-lead);
  line-height: var(--lh-lead);
  letter-spacing: var(--track-lead);
  font-weight: var(--weight-medium);
  color: var(--stage-muted);
  text-wrap: pretty;
}
/* The blank: a rule on the baseline of "I am", drawn out from the left when the sixth stop arrives */
.slot-blank {
  display: inline-block;
  width: var(--slot-blank-w);
  margin-left: var(--slot-blank-gap);
  border-bottom: var(--slot-blank-rule) solid var(--stage-accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-slot) var(--ease-exit);
}
.slot.is-blank .slot-blank {
  transform: none;
  transition-timing-function: var(--ease-enter);
  transition-delay: var(--slot-enter-delay);
}

/* Masked line reveal. Each word has its own mask, so a label that wraps reveals line by line.
   A new label rises in with --ease-enter; the old one leaves upward with --ease-exit. */
.slot .mask, .slot-w {
  display: inline-block;
  vertical-align: top;
  overflow: hidden;
  padding: var(--mask-pad-y) var(--mask-pad-x) var(--mask-pad-y) 0;
  margin: calc(-1 * var(--mask-pad-y)) calc(-1 * var(--mask-pad-x)) calc(-1 * var(--mask-pad-y)) 0;
}
.slot-line .mask { display: block; }
.slot .mask-in, .slot-w > span {
  display: inline-block;
  transform: translateY(var(--mask-travel));
  transition: transform var(--dur-slot) var(--ease-exit);
}
.slot-line .mask-in { display: block; }
.slot-unit.is-before .mask-in,
.slot-unit.is-before .slot-w > span,
.slot-lead.is-before .mask-in { transform: translateY(calc(-1 * var(--mask-travel))); }
.slot-unit.is-active .mask-in,
.slot-unit.is-active .slot-w > span,
.slot-lead.is-active .mask-in {
  transform: none;
  transition-timing-function: var(--ease-enter);
  transition-delay: calc(var(--slot-enter-delay) + var(--i, 0) * var(--slot-stagger));
}
.slot-unit.is-active .slot-line .mask-in {
  transition-delay: calc(var(--slot-enter-delay) + var(--slot-line-delay));
}
.slot-instant .slot .mask-in,
.slot-instant .slot-w > span,
.slot-instant .slot-unit,
.slot-instant .slot-units,
.slot-instant .slot-blank,
.slot-instant .rail,
.slot-instant .rail li { transition: none; }

/* Portrait: the X sits in the upper part, the copy below it over a scrim. The slot stands on the stage's foot with the
   rail beneath it, and is only as tall as the words showing (scripts/hero.js sets its height), so a short label hands
   its room to the X. A slot that shrinks waits for the old words to leave before "I am" moves down. */
@media (max-aspect-ratio: 1/1) {
  .scene .stage-copy, .still .stage-copy { grid-template-columns: minmax(0, 1fr); }
  .scene .hero-copy, .still .hero-copy { align-self: end; }
  .scene .slot { align-self: end; margin-top: 0; }
  .scene .rail { order: 3; margin-bottom: 0; margin-top: var(--space-6); }
  .scene .slot-units { grid-template-rows: minmax(0, 1fr); }
  .scene .slot-unit { align-self: end; }
  .scene .slot-units { transition: height var(--dur-slot) var(--ease-standard); }
  .scene .slot.is-shrinking .slot-units { transition-delay: var(--slot-shrink-delay); }
  .scene .stage-shade, .still .stage-shade {
    background:
      linear-gradient(to bottom, var(--stage-scrim), var(--stage-scrim-0) var(--scrim-top-h)),
      linear-gradient(to top, var(--stage-bg), var(--stage-scrim) var(--scrim-foot-h), var(--stage-scrim-mid) var(--scrim-bottom-mid), var(--stage-scrim-0) var(--scrim-bottom-h));
  }
}

/* The contact form's "Your X" field carries the scene's front door: while the field has focus a large faint X lies in
   its lower right corner, cropped by the field's edges, the X of light the open door throws on the floor. The wrapper
   is the textarea's own box, so the X follows a resize. Decorative only: the field, its label and its messages are
   unchanged, and the tint is too faint to move the text's contrast. */
.x-echo { position: relative; }
.x-echo textarea { display: block; }
.x-echo::after {
  content: "";
  position: absolute;
  inset: var(--border-control);
  border-radius: var(--radius-control);
  pointer-events: none;
  background: var(--x-echo-tint);
  -webkit-mask: url("../icons/x-opening.svg") no-repeat right calc(-1 * var(--x-echo-crop-x)) bottom calc(-1 * var(--x-echo-crop-y)) / auto var(--x-echo-size);
  mask: url("../icons/x-opening.svg") no-repeat right calc(-1 * var(--x-echo-crop-x)) bottom calc(-1 * var(--x-echo-crop-y)) / auto var(--x-echo-size);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-standard);
}
.x-echo:focus-within::after { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .scene .hero-copy .mask-in, .slot .mask-in, .slot-w > span { transform: none; }
}
