/* Part 6, Get in touch. Every selector is scoped to .contact--prompt.

   The page ends where it began, quietly. After the ink of the Impact scene
   the lake returns, full bleed and at least the height of the screen under
   the bar, but only its dark open water: no sky, no ridge and no shore, so
   it rises out of the ink above, settles into the ink below and does not
   repeat the hero.
   An ink shade gathers over the writing column and settles into the
   footer's ink at the foot.

   On that water the visitor answers the page in its own display voice: the
   title in the page's tracked capitals at the top of a centred column; the
   text box set in large light type, one paper rule under it and Send at the
   rule's right end. Send opens a row of four quiet fields under the rule,
   with Confirm in Send's place beneath them; Confirm puts the thank-you
   where the message was, in the same type, over the same rule.

   The photograph is held one screen tall and stays put while a longer form
   scrolls past it, so it covers the scene to its foot at every stage.

   Everything down to the motion blocks is the complete static section.
   Without scripting every field and Send show at once. */

.contact--prompt {
  --prompt-screen: 100vh;
  --prompt-column: 60rem;
  --prompt-pad: clamp(3.5rem, var(--prompt-screen) * 0.08, 5.5rem);
  --prompt-title-size: clamp(1.875rem, 1.2rem + 2.2vw, 2.875rem);
  --prompt-display: clamp(1.375rem, 0.95rem + 1.85vw, 2.5rem);
  --prompt-leading: 1.35;
  --prompt-lines: 4;                          /* the text box's resting height, in lines */
  --prompt-measure: 21.5em;                   /* longest display line: the question breaks before co-investing */
  --prompt-gap: clamp(2.5rem, var(--prompt-screen) * 0.06, 4rem);
  --prompt-rule-gap: clamp(1rem, var(--prompt-screen) * 0.02, 1.5rem);
  --prompt-foot: 3.5rem;                      /* from the rule to the foot of Send */
  --prompt-reveal: 0.56s;

  /* On the shaded photograph. Each tone is measured against the brightest
     water behind it: text 4.5:1 or more, lines and focus 3:1 or more. */
  --prompt-hint: #ADB2B8;                     /* the placeholder question */
  --prompt-label: var(--on-dark-muted);
  --prompt-line: rgb(250 250 248 / 0.5);      /* field underline */
  --prompt-error: #E6A796;                    /* a light rust, only for errors */
  --prompt-idle: #8E9399;                     /* Confirm while sending */

  /* The writing column follows the title at a generous, connected distance,
     and the title, the empty text box, its rule and Send stand as one group
     centred in the height of the scene, with as much photograph above as
     below. The centring is worked out from the resting size of the group,
     never from the content, so the box grows downward as words are added
     and nothing above it moves. */
  --prompt-stage: calc(var(--prompt-lines) * var(--prompt-leading) * var(--prompt-display) + var(--prompt-rule-gap) + 2px + var(--prompt-foot));
  --prompt-drop: clamp(2.5rem, var(--prompt-screen) * 0.06, 4.5rem);

  /* The scene, measured from the screen like the writing it serves:
     its height under the bar; the line where the empty writing ends (the
     foot of Send); the depth at which it has settled into ink, its foot */
  --prompt-s: calc(var(--prompt-screen) - var(--nav-h));
  --prompt-group: calc(1.2 * var(--prompt-title-size) + var(--prompt-drop) + var(--prompt-stage));
  --prompt-top: max(var(--prompt-pad), (var(--prompt-s) - var(--prompt-group)) / 2);
  --prompt-open: calc(var(--prompt-top) + var(--prompt-group));
  --prompt-sink: var(--prompt-s);

  /* The shade: ink alpha down the scene (the join with the Impact ink, head,
     body, open water) and over the writing column (base, and deep while the
     visitor writes). */
  --prompt-join: calc(var(--prompt-pad) * 2.4);   /* a long, soft rise out of the Impact ink */
  --prompt-join-mid: calc(0.96 - 0.4 * (0.96 - var(--prompt-v-head)));
  --prompt-v-head: 0.45;
  --prompt-v-body: 0.35;
  --prompt-v-lake: 0.18;
  --prompt-c-base: 0.6;
  --prompt-c-deep: 0.78;

  /* Down the scene: where the body and the open water tones sit, and where
     the water starts to settle into the footer's ink, eased so the two meet
     at the scene's foot without an edge */
  /* The fade starts a little below Send and always ends inside the scene,
     even on a short sideways screen */
  --prompt-at-body: min(calc(var(--prompt-open) + 1rem), var(--prompt-at-lake));
  --prompt-at-lake: min(calc(var(--prompt-open) + 4rem), var(--prompt-fade));
  --prompt-fade: max(var(--prompt-s) * 0.5, min(calc(var(--prompt-open) + 4rem), var(--prompt-sink) * 0.85));

  position: relative;
  display: flex;
  flex-direction: column;
  min-height: var(--prompt-s);
  padding-block: var(--prompt-top) var(--prompt-pad);
  background: var(--ink);
  color: var(--on-dark);
  color-scheme: dark;
  caret-color: var(--accent-on-dark);
  --ring: var(--on-dark);
}

@supports (height: 1svh) {
  .contact--prompt { --prompt-screen: 100svh; }
}

@media (min-width: 40rem) {
  .contact--prompt { --prompt-lines: 3; }
}

/* A wide, landscape screen: a little more air between the title and the
   question, and a shade a step deeper, as befits a larger field of water */
@media (min-width: 64rem) and (orientation: landscape) {
  .contact--prompt {
    --prompt-drop: clamp(3rem, var(--prompt-screen) * 0.08, 5.5rem);
    --prompt-v-head: 0.5;
    --prompt-v-body: 0.36;
    --prompt-v-lake: 0.3;
  }
}

.contact--prompt [hidden] { display: none !important; }

.contact--prompt ::selection { background: var(--accent-on-dark); color: var(--ink); }

/* ------------------------------------------------------------------
   The photograph and its shade
   ------------------------------------------------------------------ */

.contact--prompt .prompt__backdrop {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* One screen tall under the bar; where the form makes the scene taller,
   the view holds while the writing scrolls past, and it meets the footer
   at the scene's foot */
.contact--prompt .prompt__view {
  position: sticky;
  top: var(--nav-h);
  height: var(--prompt-s);
  overflow: hidden;
}

/* A crop of the lake's open water, 2 by 1, covering the view */
.contact--prompt .prompt__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  max-width: none;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0;
  transform-origin: 50% 0;                    /* the settle turns about the head of the view */
  filter: saturate(0.9);                      /* as the hero holds it */
}

.contact--prompt .prompt__shade,
.contact--prompt .prompt__shade::before {
  position: absolute;
  inset: 0;
}

/* Down the scene: out of the Impact scene's ink at the head, calm over the
   shore and the water, and into the footer's ink at the sink */
.contact--prompt .prompt__shade {
  background: linear-gradient(
    to bottom,
    rgb(15 16 18 / 0.96) 0,
    rgb(15 16 18 / var(--prompt-join-mid)) calc(var(--prompt-join) * 0.4),
    rgb(15 16 18 / var(--prompt-v-head)) var(--prompt-join),
    rgb(15 16 18 / var(--prompt-v-body)) var(--prompt-at-body),
    rgb(15 16 18 / var(--prompt-v-lake)) var(--prompt-at-lake),
    rgb(15 16 18 / var(--prompt-v-lake)) var(--prompt-fade),
    rgb(15 16 18 / 0.34) calc(var(--prompt-fade) + (var(--prompt-sink) - var(--prompt-fade)) * 0.3),
    rgb(15 16 18 / 0.58) calc(var(--prompt-fade) + (var(--prompt-sink) - var(--prompt-fade)) * 0.55),
    rgb(15 16 18 / 0.84) calc(var(--prompt-fade) + (var(--prompt-sink) - var(--prompt-fade)) * 0.8),
    rgb(15 16 18 / 0.96) calc(var(--prompt-fade) + (var(--prompt-sink) - var(--prompt-fade)) * 0.93),
    rgb(15 16 18 / 1) var(--prompt-sink)
  );
}

/* Across the writing column: the shade gathers where the words are and
   leaves the photograph clear at the edges. The base holds the title, the
   question and Send; below them the open water stays light. Past the sink,
   where the scene is already ink, the column lays nothing more on it, so
   no faint edge of the band can show on the flat ink. */
.contact--prompt .prompt__shade::before {
  content: "";
  --prompt-half: min(calc(var(--prompt-column) / 2), 50% - var(--gutter));
  /* where the column all but fills the screen (phones, tablets) the shade
     runs full to the edges, so no lighter strip is left along them */
  background: linear-gradient(
    to right,
    rgb(15 16 18 / 0) calc(50% - var(--prompt-half) - 12rem),
    rgb(15 16 18 / var(--prompt-c)) max(0px, 50% - var(--prompt-half) - 2rem),
    rgb(15 16 18 / var(--prompt-c)) min(100%, 50% + var(--prompt-half) + 2rem),
    rgb(15 16 18 / 0) calc(50% + var(--prompt-half) + 12rem)
  );
  --prompt-c: var(--prompt-c-base);
  --prompt-c-mask: linear-gradient(
    to bottom,
    #000 0,
    #000 calc(var(--prompt-open) + 0.5rem),
    rgb(0 0 0 / 0.15) calc(var(--prompt-open) + 5rem),
    rgb(0 0 0 / 0.15) calc(var(--prompt-sink) - 1px),
    transparent var(--prompt-sink)
  );
  -webkit-mask-image: var(--prompt-c-mask);
  mask-image: var(--prompt-c-mask);
}

/* Deep: once the visitor is writing, and while the details are open, the
   column darkens under the open water too, so every line the form can
   bring there holds its contrast. Without scripting it is always on. */
.contact--prompt .prompt__shade--deep { background: none; }

.contact--prompt .prompt__shade--deep::before {
  --prompt-c: var(--prompt-c-deep);
  --prompt-c-mask: linear-gradient(
    to bottom,
    transparent calc(var(--prompt-open) + 0.5rem),
    #000 calc(var(--prompt-open) + 3rem),
    #000 calc(var(--prompt-sink) - 1px),
    transparent var(--prompt-sink)
  );
}

html.js-contact .contact--prompt:not([data-prompt-engaged]) .prompt__shade--deep,
.contact--prompt[data-prompt-stage="sent"] .prompt__shade--deep {
  opacity: 0;
}

/* ------------------------------------------------------------------
   The writing
   ------------------------------------------------------------------ */

.contact--prompt .prompt__scene {
  position: relative;
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}

.contact--prompt .prompt__title,
.contact--prompt .prompt__form {
  width: 100%;
  max-width: var(--prompt-column);
  margin-inline: auto;
}

.contact--prompt .prompt__title {
  font-weight: 300;
  font-size: var(--prompt-title-size);
  line-height: 1.2;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  color: var(--on-dark);
  text-wrap: balance;
}

/* ------------------------------------------------------------------
   The form: one column, the Send row sharing the line under the rule with
   the message's error; the details and Confirm follow beneath it
   ------------------------------------------------------------------ */

.contact--prompt .prompt__form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  margin-top: var(--prompt-drop);
}

.contact--prompt .prompt__write { grid-column: 1 / -1; grid-row: 1; }

.contact--prompt .prompt__cell {
  position: relative;
  display: grid;
}

.contact--prompt .prompt__message,
.contact--prompt .prompt__thanks { grid-area: 1 / 1; }

/* The text box: the page's display voice, so what is written reads as
   considered as the page around it */
.contact--prompt .prompt__message {
  display: block;
  width: 100%;
  min-height: calc(var(--prompt-lines) * var(--prompt-leading) * 1em);
  max-height: max(calc(var(--prompt-lines) * var(--prompt-leading) * 1em), var(--prompt-screen) * 0.5);
  margin: 0;
  padding: 0 max(0px, 100% - var(--prompt-measure)) 0 0;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--on-dark);
  font-family: var(--font);
  font-size: var(--prompt-display);
  font-weight: 300;
  line-height: var(--prompt-leading);
  letter-spacing: -0.005em;
  caret-color: var(--accent-on-dark);
  resize: none;
  overflow-y: auto;
  field-sizing: content;
  scrollbar-width: thin;
  scrollbar-color: rgb(250 250 248 / 0.36) transparent;
  -webkit-appearance: none;
  appearance: none;
}

.contact--prompt .prompt__message:focus,
.contact--prompt .prompt__message:focus-visible { outline: none; }

.contact--prompt .prompt__message::placeholder {
  color: var(--prompt-hint);
  opacity: 1;
}

/* Once the details are open the box holds only what was written */
html.js-contact .contact--prompt[data-prompt-stage="details"] .prompt__message {
  min-height: calc(var(--prompt-leading) * 1em);
}

.contact--prompt .prompt__thanks {
  align-self: start;
  max-width: var(--prompt-measure);
  margin: 0;
  font-size: var(--prompt-display);
  font-weight: 300;
  line-height: var(--prompt-leading);
  letter-spacing: -0.005em;
  color: var(--on-dark);
  text-wrap: balance;
  opacity: 0;
  pointer-events: none;
}

.contact--prompt .prompt__thanks:focus { outline: none; }

/* Each sentence of the thank-you on its own line */
.contact--prompt .prompt__thanks-line {
  display: block;
  text-wrap: balance;
}

/* The rule: 1px of paper; while the text box has focus a 2px steel line
   runs along it from the left, and an error turns it rust */
.contact--prompt .prompt__rule {
  grid-column: 1 / -1;
  grid-row: 2;
  position: relative;
  display: block;
  height: 2px;
  margin-top: var(--prompt-rule-gap);
}

.contact--prompt .prompt__rule::before,
.contact--prompt .prompt__rule::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
}

.contact--prompt .prompt__rule::before {
  height: 1px;
  background: var(--on-dark);
}

.contact--prompt .prompt__rule::after {
  top: 0;
  background: var(--accent-on-dark);
  transform: scaleX(0);
  transform-origin: left center;
}

.contact--prompt:not([data-prompt-stage="sent"]) .prompt__write:focus-within + .prompt__rule::after { transform: scaleX(1); }

.contact--prompt .prompt__write:has([aria-invalid="true"]) + .prompt__rule::before,
.contact--prompt .prompt__write:has([aria-invalid="true"]) + .prompt__rule::after { background: var(--prompt-error); }

/* Errors */
.contact--prompt .prompt__error {
  margin: 0.5rem 0 0;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.5;
  color: var(--prompt-error);
}

.contact--prompt .prompt__note {
  grid-column: 1;
  grid-row: 3;
  align-self: start;
  display: flex;
  align-items: center;
  min-height: 2.75rem;
  margin: 0.75rem 1.5rem 0 0;
}

/* A message that could not be sent: level with Confirm */
.contact--prompt .prompt__failed {
  grid-row: 5;
  margin-top: clamp(1.75rem, var(--prompt-screen) * 0.035, 2.5rem);
}

.contact--prompt .prompt__failed a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* A fold opens and closes on its content's height */
.contact--prompt .prompt__fold {
  display: grid;
  grid-template-rows: 1fr;
  min-width: 0;
}

.contact--prompt .prompt__fold-inner { min-height: 0; overflow: hidden; }

/* The details */
.contact--prompt .prompt__details { grid-column: 1 / -1; grid-row: 4; }

.contact--prompt .prompt__fields {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  column-gap: 2rem;
  row-gap: 1.5rem;
  padding-top: clamp(1.75rem, var(--prompt-screen) * 0.035, 2.5rem);
}

@media (min-width: 37.5rem) {
  .contact--prompt .prompt__fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 70rem) {
  .contact--prompt .prompt__fields { grid-template-columns: repeat(4, minmax(0, 1fr)); }

  /* In the row of four an error may run on into the gap beside its field
     rather than break, never as far as the next field */
  .contact--prompt .prompt__field .prompt__error {
    width: max-content;
    max-width: calc(100% + 1.75rem);
  }
}

.contact--prompt .prompt__field {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.contact--prompt .prompt__label {
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: var(--track-small);
  text-transform: uppercase;
  color: var(--prompt-label);
}

.contact--prompt .prompt__input {
  display: block;
  width: 100%;
  min-height: 2.75rem;
  margin: 0.25rem 0 0;
  padding: 0.375rem 0 0.5rem;
  border: 0;
  border-bottom: 1px solid var(--prompt-line);
  border-radius: var(--radius);
  background-color: transparent;
  background-image: linear-gradient(var(--accent-on-dark), var(--accent-on-dark));
  background-repeat: no-repeat;
  background-position: left bottom;
  background-size: 0% 1px;
  color: var(--on-dark);
  font-family: var(--font);
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.4;
  caret-color: var(--accent-on-dark);
  -webkit-appearance: none;
  appearance: none;
}

@media (hover: hover) {
  .contact--prompt .prompt__input:hover { border-bottom-color: var(--on-dark); }
}

.contact--prompt .prompt__input:focus,
.contact--prompt .prompt__input:focus-visible {
  outline: none;
  border-bottom-color: var(--accent-on-dark);
  background-size: 100% 1px;
}

/* A forced-colours theme repaints the steel underline in its one text colour, so focus would show
   only as a hairline getting thicker. There the fields take the theme's own focus outline. */
@media (forced-colors: active) {
  .contact--prompt .prompt__message:focus-visible,
  .contact--prompt .prompt__input:focus-visible {
    outline: 2px solid Highlight;
    outline-offset: 4px;
  }
  /* the fields sit in the details' fold, which clips at its edges: the ring goes inside */
  .contact--prompt .prompt__input:focus-visible { outline-offset: -2px; }
}

.contact--prompt .prompt__input[aria-invalid="true"] {
  border-bottom-color: var(--prompt-error);
  background-image: linear-gradient(var(--prompt-error), var(--prompt-error));
}

/* Autofill paints no box over the photograph: the field stays clear, the
   text stays paper, and the browser's fill colour never arrives */
.contact--prompt .prompt__input:-webkit-autofill,
.contact--prompt .prompt__input:-webkit-autofill:hover,
.contact--prompt .prompt__input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--on-dark);
  caret-color: var(--accent-on-dark);
  transition: background-color 0s 86400s, color 0s 86400s;
}

/* The browser drops the focus line's gradient on a filled field; an inset
   line keeps the 2px focus mark */
.contact--prompt .prompt__input:-webkit-autofill:focus { box-shadow: inset 0 -1px 0 var(--accent-on-dark); }

.contact--prompt .prompt__input:autofill {
  -webkit-text-fill-color: var(--on-dark);
  filter: none;
}

/* Send, then Confirm, at the right end of the column. The fold keeps a
   little room around the button so its focus ring is never clipped. */
.contact--prompt .prompt__footing {
  grid-column: 2;
  grid-row: 5;
  justify-self: end;
  margin-top: clamp(1.75rem, var(--prompt-screen) * 0.035, 2.5rem);
}

html.js-contact .contact--prompt:not([data-prompt-stage]) .prompt__footing,
html.js-contact .contact--prompt[data-prompt-stage="message"] .prompt__footing {
  grid-row: 3;
  margin-top: 0.75rem;
}

.contact--prompt .prompt__footing .prompt__fold-inner {
  padding: 0.5rem;
  margin: -0.5rem;
}

.contact--prompt .prompt__button {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 2.75rem;
  min-height: 2.75rem;
  margin: 0;
  padding: 0 0 0 1rem;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--on-dark);
  font-family: var(--font);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: var(--track-small);
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.contact--prompt .prompt__arrow {
  flex: none;
  width: 1.375rem;
  height: 0.75rem;
  overflow: visible;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.25;
}

@media (hover: hover) {
  .contact--prompt .prompt__button:hover { color: var(--accent-on-dark); }
  .contact--prompt .prompt__button:hover .prompt__arrow { transform: translateX(0.25rem); }
}

.contact--prompt .prompt__button:disabled {
  color: var(--prompt-idle);
  cursor: progress;
}

.contact--prompt .prompt__button:disabled .prompt__arrow { transform: none; }

/* ------------------------------------------------------------------
   The staged flow (only where scripting runs)
   ------------------------------------------------------------------ */

html.js-contact .contact--prompt:not([data-prompt-stage="details"]) .prompt__details {
  grid-template-rows: 0fr;
  visibility: hidden;
}

html.js-contact .contact--prompt:not([data-prompt-stage="details"]) .prompt__field {
  opacity: 0;
  transform: translateY(1rem);
}

.contact--prompt[data-prompt-stage="sent"] .prompt__fold {
  grid-template-rows: 0fr;
  margin-top: 0;
  opacity: 0;
  visibility: hidden;
}

.contact--prompt[data-prompt-stage="sent"] .prompt__message {
  position: absolute;
  inset: 0 0 auto;
  opacity: 0;
  filter: blur(0.3em);
  pointer-events: none;
}

.contact--prompt[data-prompt-stage="sent"] .prompt__thanks {
  opacity: 1;
  pointer-events: auto;
}

/* ------------------------------------------------------------------
   Time-based motion for the steps: the box eases to its content, the
   fields rise from the rule one after another, Confirm settles into
   Send's place; on sending the words dissolve and the thank-you rises
   into their place while the shade lifts off the water again. The
   column's shade deepens slowly as the visitor starts to write. Instant
   where motion is reduced.
   ------------------------------------------------------------------ */

@media (prefers-reduced-motion: no-preference) {
  .contact--prompt .prompt__write:focus-within + .prompt__rule::after { transition: transform 0.7s var(--ease-out); }

  .contact--prompt .prompt__shade--deep { transition: opacity 0.9s var(--ease-out); }

  .contact--prompt[data-prompt-stage="sent"] .prompt__shade--deep { transition: opacity 1.4s var(--ease-out) 0.5s; }

  .contact--prompt .prompt__message {
    transition:
      min-height var(--prompt-reveal) var(--ease-out),
      opacity 0.42s var(--ease-out),
      filter 0.6s var(--ease-out);
  }

  .contact--prompt .prompt__thanks { transform: translateY(0.45em); }

  .contact--prompt[data-prompt-stage="sent"] .prompt__thanks {
    transform: none;
    transition: opacity 0.8s var(--ease-out) 0.24s, transform 1s var(--ease-out) 0.24s;
  }

  .contact--prompt .prompt__fold {
    transition:
      grid-template-rows var(--prompt-reveal) var(--ease-out),
      margin-top var(--prompt-reveal) var(--ease-out),
      opacity 0.4s var(--ease-out),
      visibility 0s linear 0s;
  }

  html.js-contact .contact--prompt:not([data-prompt-stage="details"]) .prompt__details,
  .contact--prompt[data-prompt-stage="sent"] .prompt__fold {
    transition:
      grid-template-rows var(--prompt-reveal) var(--ease-out),
      margin-top var(--prompt-reveal) var(--ease-out),
      opacity 0.3s var(--ease-out),
      visibility 0s linear var(--prompt-reveal);
  }

  .contact--prompt .prompt__field {
    transition: opacity 0.5s var(--ease-out), transform 0.7s var(--ease-out);
  }

  .contact--prompt[data-prompt-stage="details"] .prompt__field:nth-child(1) { transition-delay: 0.1s; }
  .contact--prompt[data-prompt-stage="details"] .prompt__field:nth-child(2) { transition-delay: 0.16s; }
  .contact--prompt[data-prompt-stage="details"] .prompt__field:nth-child(3) { transition-delay: 0.22s; }
  .contact--prompt[data-prompt-stage="details"] .prompt__field:nth-child(4) { transition-delay: 0.28s; }

  .contact--prompt[data-prompt-stage="details"] .prompt__confirm {
    animation: contact-prompt-settle 0.6s var(--ease-out) 0.2s both;
  }

  .contact--prompt .prompt__input { transition: border-color 0.3s var(--ease-out); }
  .contact--prompt .prompt__input:focus { transition: border-color 0.3s var(--ease-out), background-size 0.6s var(--ease-out); }
  .contact--prompt .prompt__button { transition: color 0.3s var(--ease-out); }
  .contact--prompt .prompt__arrow { transition: transform 0.45s var(--ease-out); }
}

@keyframes contact-prompt-settle {
  from { opacity: 0; transform: translateX(-0.75rem); }
  to { opacity: 1; transform: translateX(0); }
}

/* ------------------------------------------------------------------
   Scroll choreography: as the scene comes up out of the Impact ink, the
   photograph settles from a slight scale about its shoreline, the title
   rises, then the writing area rises and the rule draws from the left
   under it. The photograph has settled by 85% of the scene's entry and
   the writing area as soon as it is wholly on screen, both well before
   the Contact link's landing position. Once the visitor is in the form
   the writing area and its rule stand resolved wherever they scroll, so
   the box is never caught half risen where it can be typed in, and a
   long message that carries the rule low on the screen never undraws it.
   The fallback in contact.js mirrors every animation here.
   ------------------------------------------------------------------ */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .contact--prompt { view-timeline: --prompt-scene block; }

    .contact--prompt .prompt__photo {
      animation: contact-prompt-photo linear both;
      animation-timeline: --prompt-scene;
      animation-range: entry 0% entry 85%;
    }

    .contact--prompt .prompt__title {
      animation: contact-prompt-rise linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 22%;
    }

    .contact--prompt .prompt__write {
      animation: contact-prompt-lift linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 100%;
    }

    .contact--prompt .prompt__rule {
      animation: contact-prompt-draw linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 20%;
    }

    .contact--prompt[data-prompt-engaged] .prompt__write,
    .contact--prompt[data-prompt-engaged] .prompt__rule { animation: none; }
  }
}

/* Where scroll-fallback.js plays these scenes instead, the CSS
   versions stand down */
@media (prefers-reduced-motion: no-preference) {
  html.sdt-fallback .contact--prompt .prompt__photo,
  html.sdt-fallback .contact--prompt .prompt__title,
  html.sdt-fallback .contact--prompt .prompt__write,
  html.sdt-fallback .contact--prompt .prompt__rule {
    animation: none;
  }
}

@keyframes contact-prompt-photo {
  from { transform: scale(1.08); }
  to { transform: scale(1); }
}

@keyframes contact-prompt-rise {
  from { opacity: 0; transform: translateY(1.5rem); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes contact-prompt-lift {
  from { opacity: 0; transform: translateY(2.5rem); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes contact-prompt-draw {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0 0 0 0); }
}
