/* Act 1, the field. Owned by the hero agent.
   The act reads as its moments stacked: the hero moment (100vh, or taller
   on a short stage), the open beat (48vh), the turn moment (100vh), then a
   short hold on the pinned frame (--field-hold, set by js/diagram.js) over
   which the stage and the statement stay pinned. No negative margin: the
   services band does not climb over the act, it follows it; when the hold
   ends the stage and the statement scroll out together at full ink and the
   band arrives directly behind them, so no frame is ever an empty panel.
   z-index 0 keeps the whole act in one stacking context painted beneath
   the band that follows it. Scroll progress drives the workflow drawing in
   js/diagram.js from a tangle of workarounds to one clean line. */

.field {
  position: relative;
  z-index: 0;
}

/* The hold on the pinned frame: a block at the foot of the act, inside it,
   so the sticky stage and statement keep their pin for its height. */
.field::after {
  content: '';
  display: block;
  height: var(--field-hold, 40vh);
}

/* The open beat between the hero copy and the statement, where the drawing
   spreads to the full stage and untangles. Nothing is rendered in it. */
.field .field__moment--work { height: 48vh; }

.field__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}

/* The drawing fills the stage. js/diagram.js sizes the viewBox to the stage
   box and lays the diagram out in stage pixels. */
.field__diagram {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
  overflow: visible;
}

/* The diagram's parts. Hairline strokes only; colours are the tokens, set
   here so the script carries no colour of its own. */
.diagram__box {
  fill: var(--color-loam);
  stroke: var(--color-fallow);
  stroke-width: var(--hairline);
  vector-effect: non-scaling-stroke;
}

.diagram__node--side .diagram__box,
.diagram__node--dup .diagram__box { stroke: var(--color-rule-dark); }

.diagram__label {
  font-family: var(--font-utility);
  font-size: var(--text-12);
  font-weight: var(--weight-medium);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  fill: var(--color-chaff);
}

.diagram__node--side .diagram__label,
.diagram__node--dup .diagram__label { fill: var(--color-fallow); }

.diagram__line {
  fill: none;
  stroke: var(--color-fallow);
  stroke-width: var(--hairline);
  stroke-linecap: butt;
  stroke-linejoin: miter;
}

.diagram__line--dashed { stroke-dasharray: 3 5; }
.diagram__line--clean { stroke: var(--color-terrace); }

.diagram__note {
  font-family: var(--font-utility);
  font-size: var(--text-12);
  fill: var(--color-fallow);
}

.diagram__numeral {
  font-family: var(--font-utility);
  font-size: var(--text-12);
  letter-spacing: 0.1em;
  fill: var(--color-terrace);
}

/* The resting line's second register: under each step, what it means for
   the owner. Inter 14, Fallow. js/diagram.js shows it with the numerals
   and keeps it with the row through the pinned frame. */
.diagram__caption {
  font-family: var(--font-body);
  font-size: var(--text-14);
  fill: var(--color-fallow);
}

/* A packet: a short Terrace dash travelling a route, drawn by js/diagram.js
   only when motion is allowed. A dash, never a dot; butt caps, no radius. */
.diagram__packet {
  fill: none;
  stroke: var(--color-terrace);
  stroke-width: 3px;
  stroke-linecap: butt;
}

/* A short vertical fade at the stage foot. A gradient between two states of
   the same ground colour, not a shadow and not a glow. The band covers the
   stage rather than abutting it, so this only softens the last rows and the
   near lines survive to the foot of the viewport. */
.field__haze {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: var(--space-32);
  pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--color-loam));
}

.field__moment {
  position: relative;
  z-index: 2;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.field__moment--hero { margin-top: -100vh; height: auto; min-height: 100vh; }

/* A short stage (js/diagram.js sets .field--short when the stage is shorter
   than the copy block plus the drawing's minimum height): the copy has the
   stage to itself, the moment grows 192 past the stage so the copy has room
   and the drawing, started only once the copy has dissolved, has a beat to
   be read before the statement arrives. */
.field--short .field__moment--hero { min-height: calc(100vh + var(--space-192)); }

/* The hero copy is pinned to the upper part of the stage rather than centred:
   the eyebrow lands 96 under the header foot on any viewport height, and the
   ground below the copy stays open for the drawing, which is the act's one
   picture. Centring left a slack band of bare Loam above the eyebrow. */
.field__moment--hero {
  justify-content: center;
  padding-top: var(--space-64);
}

/* --hero-fade is set on the section by js/diagram.js: 1 while the copy block
   sits below the header foot, 0 once it has climbed past it, so the last
   lead line and the CTA row never share a frame with the statement
   entering at the viewport foot. Under reduced motion the script sets a
   hard step instead of a gradient. */
.field__moment--hero .shell { opacity: var(--hero-fade, 1); }

/* ------------------------------------------------------------- hero moment */

/* Option 4, the workflow drawn. The copy holds the left five columns; the
   diagram, drawn by js/diagram.js, owns the right two thirds of the stage and
   its tangle runs a little behind the claim. The type always wins: the lines
   are hairlines and the boxes are Loam. */
.hero__copy {
  max-width: 560px;
}

.claim {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: var(--text-73);
  line-height: var(--leading-73);
  letter-spacing: -0.015em;
  max-width: 560px;
}

.lead {
  margin-top: var(--space-32);
  font-size: var(--text-17);
  line-height: var(--leading-17);
  color: var(--color-fallow);
  max-width: 480px;
}

/* One solid control and one text link, so the pair has a clear first and
   second, not two boxes of equal weight. */
.hero__actions {
  margin-top: var(--space-32);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-24);
}

.hero__more {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  font-size: var(--text-17);
  line-height: var(--leading-17);
  font-weight: var(--weight-medium);
  color: var(--color-chaff);
  text-decoration: none;
  transition: color 200ms ease;
}

.hero__more-label {
  text-decoration-line: underline;
  text-decoration-thickness: var(--hairline);
  text-decoration-color: var(--color-fallow);
  text-underline-offset: 4px;
  transition: text-decoration-color 200ms ease;
}

.hero__more-arrow {
  color: var(--color-terrace);
  transition: transform 200ms ease;
}

.hero__more:hover { color: var(--color-terrace); }
.hero__more:hover .hero__more-label { text-decoration-color: var(--color-terrace); }

@media (prefers-reduced-motion: no-preference) {
  .hero__more:hover .hero__more-arrow { transform: translateY(4px); }
}

/* The hero's solid control is Chaff, not Terrace: over the drawing the only
   signal colour is the clean line, and a white block on Loam reads as a
   crisp editorial control rather than a flat teal slab. Hover goes Terrace. */
.hero__actions .control--solid { background: var(--color-chaff); }
.hero__actions .control--solid:hover { background: var(--color-terrace); }

/* The quiet control's Loam fill over the near field is set globally in
   base.css (.ground--loam .control--quiet). */

/* The stamp row at the stage foot: place at the left, local time at the
   right, the scroll cue between them. Mono 12, Fallow, on the same baseline
   as the cue. js/diagram.js keeps the clock and retires the row with the cue. */
.field__stamp {
  position: absolute;
  inset-inline: 0;
  bottom: var(--space-48);
  z-index: 1;
  pointer-events: none;
}

.field__stamp .shell {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
}

.field__stamp-item {
  font-family: var(--font-utility);
  font-size: var(--text-12);
  line-height: var(--leading-12);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-fallow);
}

.field__stamp-item b {
  font-weight: var(--weight-medium);
  color: var(--color-chaff);
}

.field__stamp--hidden { opacity: 0; }

@media (prefers-reduced-motion: no-preference) {
  .field__stamp { transition: opacity 400ms ease; }
}

/* The scroll cue lives in the stage, so it is anchored to the viewport
   foot rather than to the hero copy. js/diagram.js retires it once the visitor
   has scrolled past 80px. */
.field__cue {
  position: absolute;
  bottom: var(--space-48);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-8);
  z-index: 1;
}

.field__cue--hidden { opacity: 0; }

@media (prefers-reduced-motion: no-preference) {
  .field__cue { transition: opacity 400ms ease; }
}

.field__cue-label {
  font-family: var(--font-utility);
  font-size: var(--text-12);
  line-height: var(--leading-12);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-fallow);
}

.field__cue-rule {
  display: block;
  width: var(--hairline);
  height: var(--space-48);
  background: var(--color-rule-dark);
  position: relative;
  overflow: hidden;
}

@media (prefers-reduced-motion: no-preference) {
  .field__cue-rule::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    top: 0;
    height: var(--space-16);
    background: var(--color-terrace);
    animation: cue-drop 2200ms cubic-bezier(0.6, 0, 0.4, 1) infinite;
  }

  @keyframes cue-drop {
    0% { transform: translateY(-16px); }
    60% { transform: translateY(48px); }
    100% { transform: translateY(48px); }
  }
}

/* ------------------------------------------------------------- turn moment */

/* The turn statement holds the screen while the services band sweeps up to
   answer it. The moment sets the statement down from its centre: at the
   pinned frame the clean row (numerals, boxes, captions) rides up to sit
   48 above the statement, and the whole block (row, statement, note) then
   sits centred in the stage under the header, with about as much Loam
   above the numerals as below the note. js/diagram.js reads the
   statement's place from the layout. */
.field__moment--turn {
  position: sticky;
  top: 0;
  padding-top: calc(var(--space-192) + var(--space-32));
}

/* --turn-fade is set on the section by js/diagram.js from scroll progress:
   1 while the statement holds, falling only over the last 48 before the
   services band reaches it, so it reads as covered, not dimmed. */
.turn__text {
  opacity: var(--turn-fade, 1);
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: var(--text-51);
  line-height: var(--leading-51);
  letter-spacing: -0.01em;
  max-width: 928px;
}

/* The answer starts on its own line, so the colour change and the line
   change happen together rather than mid line. */
.turn__line { display: block; }
.turn__line--quiet { color: var(--color-fallow); }

/* The statement's caption: a mono figure line under a hairline that names
   what the drawing has done since the top of the page, so the second screen
   is a beat with its own structure, not the hero frame repeated. */
.turn__note {
  opacity: var(--turn-fade, 1);
  margin-top: var(--space-48);
  padding-top: var(--space-16);
  border-top: var(--hairline) solid var(--color-rule-dark);
  max-width: 480px;
  display: flex;
  gap: var(--space-24);
  font-family: var(--font-utility);
  font-size: var(--text-14);
  line-height: var(--leading-14);
  color: var(--color-fallow);
}

.turn__note-fig {
  flex: none;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-terrace);
}

/* ------------------------------------------------------------- breakpoints */

@media (max-width: 1023px) {
  .claim { font-size: var(--text-61); line-height: var(--leading-61); }

  .hero__copy, .claim { max-width: 480px; }
  .turn__text { font-size: var(--text-42); line-height: var(--leading-42); }
}

@media (max-width: 767px) {
  .claim { font-size: var(--text-42); line-height: var(--leading-42); }

  /* One line eyebrow: the second term is dropped on phones. */
  .hero__eyebrow-tail { display: none; }

  /* The solid control takes the full measure, the text link sits under it,
     and the scroll cue is retired: there is no room under the CTAs. */
  .hero__actions { flex-direction: column; align-items: stretch; gap: var(--space-16); }
  .hero__actions .control { display: block; text-align: center; }
  .hero__actions .control__face { display: block; }
  .hero__more { justify-content: center; }
  .field__cue { display: none; }
  .field__stamp { display: none; }
  /* Phones: copy at the top of the stage, set tight, so the band under it
     gives the drawing room: the lead and the controls close up to 16. */
  .field__moment--hero { justify-content: flex-start; padding-top: calc(var(--space-96) + var(--space-32)); }
  .lead { margin-top: var(--space-16); }
  .hero__actions { margin-top: var(--space-16); }


  /* The statement at 29 on phones: four lines. The moment sets it 448
     down from the top rather than centring it, so the two clean rows of
     the drawing (128 apart, captions under each, 48 above the statement)
     sit over it at the pinned frame with the block centred under the
     header. On a short stage (six lines at 375 wide) it sets 384 down,
     which is all the stage has. */
  .turn__text { font-size: var(--text-29); line-height: var(--leading-29); }
  .field__moment--turn { justify-content: flex-start; padding-top: calc(var(--space-192) * 2 + var(--space-64)); }
  /* Short stage: the statement block is taller than the stage, so the turn
     moment flows instead of pinning, the stage behind it is sticky only
     until the moment has passed, and the band follows 96 under the note.
     No hold on a short stage. */
  .field--short .field__moment--turn { position: static; height: auto; min-height: 0; padding-top: var(--space-96); padding-bottom: var(--space-96); }
  .field--short::after { height: 0; }
  .turn__note { margin-top: var(--space-32); flex-direction: column; gap: var(--space-8); }
}


/* ------------------------------------------------------------- the word
   Set in the open beat, top left of the stage, above the untangling
   drawing. The first half arrives as the tangle spreads to fill the stage
   (the whole picture), the second as it cleans (simplified). Both leave as
   the statement arrives. The three variables are written by js/diagram.js. */
.field__word {
  position: absolute;
  left: 50%;
  top: calc(var(--space-64) + var(--space-64));
  width: 100%;
  max-width: var(--grid-content);
  transform: translateX(-50%);
  padding-inline: var(--grid-margin);
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: var(--text-51);
  line-height: var(--leading-51);
  letter-spacing: -0.01em;
  color: var(--color-chaff);
  pointer-events: none;
  z-index: 1;
}

@media (min-width: 1216px) { .field__word { padding-inline: 0; } }

.field__word-a { opacity: calc(var(--word-a, 0) * var(--beat-fade, 1)); }
.field__word-b { opacity: calc(var(--word-b, 0) * var(--beat-fade, 1)); color: var(--color-terrace); }

@media (prefers-reduced-motion: no-preference) {
  .field__word-a, .field__word-b { transition: opacity 160ms linear; }
}

@media (max-width: 767px) {
  .field__word {
    top: var(--space-96);
    padding-inline: var(--grid-margin-mobile);
    font-size: var(--text-35);
    line-height: var(--leading-35);
  }
}

/* Under reduced motion the still frame is the clean row; the word stands. */
@media (prefers-reduced-motion: reduce) {
  .field__word-a, .field__word-b { opacity: 1; }
}
