/* ==========================================================================
   Contact (contact.html; after spinta.co.uk/contact)
   1. Start your project: the intro and its three steps, held beside the
      form on wide screens, and the form (chips, then the fields on ruled
      lines, then Send). Sent, the title turns to "Nearly there." and a note
      takes the form's place.
   2. Or reach us directly: the email rows, and a card with the studio's
      local time (its digits roll as they change).
   3. What happens next: the four steps on a rail, with a line that fills
      down it as you read, lighting each step as it passes.
   4. Where we are: "Local enough to sit in your shop."
   The motion (contact.js): each block plays in as it arrives: titles rise
   line by line out of masks, the form's fields follow one another, rows
   draw their hairlines. A focused field draws an ink line along its foot.
   Hover (desktop): rows slide and show Copy; touch gets press states and
   an always-visible Copy.
   ========================================================================== */

.contact {
  position: relative;
  background: var(--bone);
}

/* Paper grain, as on the rest of the site. */
.contact::before {
  content: "";
  position: absolute;
  inset: 0;
  background: url("../assets/textures/grain.webp") repeat;
  background-size: 160px 160px;
  opacity: 0.55;
  pointer-events: none;
}

.contact > * {
  position: relative;
}

/* One mask per line (they rise in). The padding keeps descenders. */
.cline {
  display: block;
  overflow: clip;
  padding-bottom: 0.1em;
  margin-bottom: -0.1em;
}

.cline > span {
  display: inline-block;
}

.csec-title {
  font-size: clamp(2.25rem, 4vw, 4.75rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.038em;
}

/* ------------------------------------------------------------------ 1. start */

.cstart {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 56px clamp(40px, 6vw, 128px);
  padding: calc(var(--header-h) + clamp(28px, 6vh, 88px)) var(--gutter) clamp(96px, 15vh, 180px);
}

.cstart__intro {
  position: sticky;
  top: calc(var(--header-compact) + clamp(24px, 4vh, 48px));
  align-self: start;
}

/* As the hero's status: an ink dot breathing in a frosted pill. */
.cstart__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px 10px 12px;
  letter-spacing: 0.1em;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgb(247 245 242 / 0.72);
}

.cstart__pulse,
.cclock__dot {
  position: relative;
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ink);
}

.cstart__pulse::after,
.cclock__dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--ink);
  animation: contact-pulse 2.4s var(--ease-out) infinite;
}

@keyframes contact-pulse {
  0% {
    opacity: 0.45;
    transform: scale(1);
  }
  70%,
  100% {
    opacity: 0;
    transform: scale(3.2);
  }
}

.cstart__title {
  margin-top: clamp(24px, 3.4vh, 40px);
  font-size: clamp(2.75rem, 5.4vw, 6.5rem);
  font-weight: 500;
  line-height: 0.98;
  letter-spacing: -0.045em;
}

.cstart__say {
  display: block;
}

.cstart__say[hidden] {
  display: none;
}

/* The title turning to "Nearly there.": its lines rise in again. */
.cstart__say.is-new .cline > span {
  animation: contact-line 1100ms var(--ease-out) both;
  animation-delay: calc(var(--l, 0) * 90ms);
}

@keyframes contact-line {
  from {
    translate: 0 106%;
  }
}

.cstart__lede {
  max-width: 36ch;
  margin-top: clamp(20px, 2.6vh, 32px);
  font-size: clamp(1rem, 0.95rem + 0.2vw, 1.1875rem);
  line-height: 1.6;
  color: var(--text-mute);
  text-wrap: pretty;
}

.cstart__steps {
  display: grid;
  gap: 18px;
  margin: clamp(36px, 5.5vh, 64px) 0 0;
  padding: 0;
  list-style: none;
}

.cstart__steps li {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr);
  align-items: baseline;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--line);
  font-size: 1rem;
  line-height: 1.45;
}

.cstart__n {
  color: var(--text-faint);
}

/* ------------------------------------------------------------------ the form */

.cform {
  display: grid;
  gap: clamp(28px, 4vh, 44px);
}

.cform[hidden] {
  display: none;
}

.cform__needs {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.cform__label {
  display: block;
  padding: 0;
  letter-spacing: 0.12em;
  color: var(--text-mute);
}

.cform__needs .enquiry__chips {
  margin-top: 16px;
}

.cform .enquiry__chip span {
  transition:
    background-color 250ms ease,
    border-color 250ms ease,
    color 250ms ease,
    scale 200ms var(--ease-out);
}

.cform .enquiry__chip:active span {
  scale: 0.95;
}

.cform__pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(28px, 4vh, 44px) clamp(24px, 2.4vw, 44px);
}

/* A field: its label, the input on a ruled line, an ink line that draws
   along the foot while it has focus, and room for a message under it. */
.cform__field {
  display: grid;
  grid-template-areas:
    "label"
    "input"
    "err";
  row-gap: 6px;
}

.cform__field .cform__label {
  grid-area: label;
}

.cform__input {
  grid-area: input;
  width: 100%;
  height: 52px;
  padding: 0;
  font: inherit;
  font-size: 1.0625rem;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid rgb(17 17 17 / 0.2);
  border-radius: 0;
  transition: border-color 250ms ease;
}

.cform__input::placeholder {
  color: var(--text-faint);
  transition: opacity 250ms ease;
}

.cform__input:focus {
  outline: none;
}

.cform__input:focus::placeholder {
  opacity: 0.5;
}

/* Autofill keeps the paper, not the browser's tint. */
.cform__input:-webkit-autofill {
  -webkit-text-fill-color: var(--ink);
  box-shadow: 0 0 0 100px var(--bone) inset;
}

.cform__input--area {
  height: auto;
  min-height: 8.5em;
  padding-top: 12px;
  line-height: 1.5;
  resize: vertical;
}

.cform__rule {
  grid-area: input;
  align-self: end;
  height: 2px;
  margin-bottom: -1px;
  background: var(--ink);
  scale: 0 1;
  transform-origin: 0 50%;
  pointer-events: none;
  transition: scale 600ms var(--ease-out);
}

.cform__field:focus-within .cform__rule {
  scale: 1 1;
}

.cform__field.is-invalid .cform__rule {
  scale: 1 1;
  background: #b42318;
}

.cform__err {
  grid-area: err;
  font-size: 0.8125rem;
  line-height: 1.4;
  color: #b42318;
}

.cform__err:empty {
  display: none;
}

.cform__field.is-invalid .cform__err {
  animation: contact-err 400ms var(--ease-out);
}

@keyframes contact-err {
  from {
    opacity: 0;
    translate: 0 -6px;
  }
}

.cform__foot {
  display: grid;
  gap: 14px;
  margin-top: 4px;
}

.cform__send {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  height: 60px;
  overflow: hidden;
  font-size: 1rem;
  font-weight: 500;
  color: var(--white);
  background: var(--ink);
  border-radius: 999px;
  transition:
    background-color 300ms ease,
    scale 240ms var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}

.cform__send svg {
  width: 16px;
  height: 16px;
  transition:
    translate 420ms var(--ease-out),
    rotate 420ms var(--ease-out);
}

.cform__send:active {
  scale: 0.985;
}

.cform__send:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
}

.cform__note {
  font-size: 0.8125rem;
  color: var(--text-faint);
  text-align: center;
}

.cform__note a {
  color: var(--text-mute);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* Sending: the arrow keeps setting off until the answer comes back
   (enquiry-nudge, in enquiry.css). */
.cform__send[aria-busy="true"] {
  cursor: progress;
}

.cform__send[aria-busy="true"] svg {
  animation: enquiry-nudge 900ms var(--ease-out) infinite;
}

/* Why it didn't send, above the note (empty, and gone, until then). */
.cform__status {
  font-size: 0.9375rem;
  line-height: 1.5;
  color: #b42318;
  text-align: center;
  text-wrap: pretty;
}

.cform__status:empty {
  display: none;
}

.cform__status a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* ------------------------------------------------------------------ sent */

.cdone {
  display: grid;
  justify-items: start;
  gap: 18px;
  padding-top: clamp(8px, 2vh, 24px);
}

.cdone[hidden] {
  display: none;
}

.cdone:focus {
  outline: none;
}

.cdone__label {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  letter-spacing: 0.12em;
}

.cdone__tick {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  color: var(--white);
  background: var(--ink);
}

.cdone__tick svg {
  width: 14px;
  height: 14px;
}

.cdone__tick path {
  stroke-dasharray: 16;
  stroke-dashoffset: 16;
}

.cdone.is-shown .cdone__tick path {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 600ms var(--ease-out) 250ms;
}

.cdone__text {
  max-width: 34ch;
  font-size: clamp(1.25rem, 1.1rem + 0.5vw, 1.75rem);
  line-height: 1.35;
  letter-spacing: -0.02em;
  text-wrap: pretty;
}

.cdone__text--small {
  max-width: 48ch;
  font-size: 1rem;
  line-height: 1.6;
  letter-spacing: 0;
  color: var(--text-mute);
}

.cdone__text a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

.cdone__edit {
  min-height: 44px;
  margin-top: 8px;
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.cdone.is-shown > * {
  animation: contact-rise 800ms var(--ease-out) both;
}

.cdone.is-shown > :nth-child(2) {
  animation-delay: 80ms;
}

.cdone.is-shown > :nth-child(3) {
  animation-delay: 160ms;
}

.cdone.is-shown > :nth-child(4) {
  animation-delay: 240ms;
}

@keyframes contact-rise {
  from {
    opacity: 0;
    translate: 0 18px;
  }
}

/* ------------------------------------------------------------------ 2. direct */

.cdirect {
  padding: clamp(88px, 14vh, 160px) var(--gutter);
  border-top: 1px solid var(--line);
}

.cdirect__grid {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  align-items: start;
  gap: 48px clamp(40px, 6vw, 128px);
  margin-top: clamp(48px, 8vh, 88px);
}

.cdirect__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.crow {
  position: relative;
  padding: 26px 0;
}

/* The hairline under a row (its own layer, so it can draw in). */
.crow::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: rgb(17 17 17 / 0.16);
  transform-origin: 0 50%;
}

.crow__label {
  letter-spacing: 0.12em;
  color: var(--text-faint);
}

.crow__main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 48px;
  margin-top: 8px;
}

.crow__link {
  min-width: 0;
  font-size: clamp(1.25rem, 1rem + 1.2vw, 2.25rem);
  font-weight: 500;
  letter-spacing: -0.03em;
  overflow-wrap: anywhere;
  transition: translate 500ms var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}

.crow__link:active {
  translate: 6px 0;
}

.crow__copy,
.crow__hint {
  flex: none;
  letter-spacing: 0.14em;
  color: var(--text-mute);
}

.crow__copy {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  transition:
    color 250ms ease,
    background-color 250ms ease,
    border-color 250ms ease,
    opacity 250ms ease,
    scale 200ms var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}

.crow__copy:active {
  scale: 0.94;
}

.crow__copy.is-copied {
  color: var(--white);
  background: var(--ink);
  border-color: var(--ink);
}

/* The studio's clock. */
.cclock {
  padding: clamp(24px, 2.4vw, 36px);
  border: 1px solid var(--line);
  border-radius: 18px;
  background: rgb(255 255 255 / 0.55);
}

.cclock__label {
  display: flex;
  align-items: center;
  gap: 12px;
  letter-spacing: 0.12em;
  color: var(--text-mute);
}

.cclock__time {
  margin-top: clamp(18px, 2.4vh, 28px);
  font-size: clamp(3.5rem, 7.4vw, 9rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* HH:MM, with the seconds small at the top right, like a stopwatch. */
.cclock__face {
  display: inline-flex;
  align-items: flex-start;
}

/* Each digit in its own slot: a changed one rolls up into place. */
.cclock__d {
  display: inline-block;
  overflow: clip;
  vertical-align: top;
}

.cclock__d > span {
  display: inline-block;
}

.cclock__d.is-tick > span {
  animation: contact-digit 520ms var(--ease-out);
}

@keyframes contact-digit {
  from {
    opacity: 0;
    translate: 0 60%;
  }
}

.cclock__sec {
  display: inline-flex;
  margin: 0.1em 0 0 0.14em;
  font-size: 0.3em;
  letter-spacing: -0.02em;
  color: var(--text-faint);
}

.cclock__zone {
  margin-top: 10px;
  letter-spacing: 0.12em;
  color: var(--text-faint);
}

.cclock__note {
  max-width: 32ch;
  margin-top: clamp(22px, 3vh, 34px);
  padding-top: 18px;
  border-top: 1px solid var(--line);
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--text-mute);
}

/* ------------------------------------------------------------------ 3. next */

.cnext {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 56px clamp(40px, 6vw, 128px);
  padding: clamp(88px, 14vh, 160px) var(--gutter) clamp(104px, 16vh, 190px);
  border-top: 1px solid var(--line);
}

.cnext__head {
  position: sticky;
  top: calc(var(--header-compact) + clamp(24px, 4vh, 48px));
  align-self: start;
}

/* The rail: a hairline down the left, an ink line filling it as you read
   (contact.js sets its scale), and a dot per step that fills as it passes. */
.cnext__rail {
  position: relative;
  padding-left: 48px;
}

.cnext__track {
  position: absolute;
  top: 10px;
  bottom: 10px;
  left: 7px;
  width: 1px;
  background: rgb(17 17 17 / 0.14);
}

.cnext__fill {
  position: absolute;
  inset: 0;
  background: var(--ink);
  transform: scaleY(0);
  transform-origin: 50% 0;
}

.cnext__list {
  display: grid;
  gap: clamp(52px, 9vh, 104px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cnext__step {
  position: relative;
}

.cnext__step::before {
  content: "";
  position: absolute;
  top: 3px;
  left: -48px;
  width: 15px;
  height: 15px;
  border: 1px solid rgb(17 17 17 / 0.3);
  border-radius: 50%;
  background: var(--bone);
  transition:
    background-color 400ms ease,
    border-color 400ms ease,
    scale 500ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.cnext__step.is-on::before {
  border-color: var(--ink);
  background: var(--ink);
  scale: 1.15;
}

.cnext__n {
  color: var(--text-faint);
  transition: color 400ms ease;
}

.cnext__step.is-on .cnext__n {
  color: var(--ink);
}

.cnext__title {
  margin-top: 12px;
  font-size: clamp(1.375rem, 1.1rem + 0.9vw, 2.25rem);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.03em;
}

.cnext__text {
  max-width: 44ch;
  margin-top: 12px;
  font-size: clamp(1rem, 0.95rem + 0.15vw, 1.125rem);
  line-height: 1.6;
  color: var(--text-mute);
  text-wrap: pretty;
}

/* ------------------------------------------------------------------ 4. place */

.cplace {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 40px 80px;
  padding: clamp(88px, 14vh, 160px) var(--gutter);
  border-top: 1px solid var(--line);
}

.cplace__where {
  display: grid;
  gap: 8px;
  letter-spacing: 0.12em;
  color: var(--text-mute);
}

.cplace__say {
  text-align: right;
}

.cplace__title {
  font-size: clamp(2rem, 3.8vw, 4.5rem);
  font-weight: 500;
  line-height: 1.02;
  letter-spacing: -0.038em;
}

.cplace__text {
  margin-top: 16px;
  font-size: clamp(1rem, 0.95rem + 0.15vw, 1.125rem);
  color: var(--text-mute);
}

/* ------------------------------------------------------------------ hover */

@media (hover: hover) and (pointer: fine) {
  .cform__send:hover {
    background: #262626;
  }

  .cform__send:hover svg {
    translate: 3px 0;
  }

  .crow:hover .crow__link {
    translate: 8px 0;
  }

  /* Copy waits for the row's hover on desktop. */
  .crow__copy {
    opacity: 0;
  }

  .crow:hover .crow__copy,
  .crow__copy:focus-visible,
  .crow__copy.is-copied {
    opacity: 1;
  }

  .crow__copy:hover {
    color: var(--ink);
    border-color: var(--ink);
  }

  .cdone__edit:hover {
    text-decoration-thickness: 2px;
  }
}

/* ------------------------------------------------------------------ narrow */

@media (max-width: 1023px) {
  .cstart,
  .cnext {
    grid-template-columns: minmax(0, 1fr);
  }

  .cstart__intro,
  .cnext__head {
    position: static;
  }

  .cstart__steps {
    max-width: 560px;
  }

  .cdirect__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .cclock {
    max-width: 520px;
  }
}

@media (max-width: 719px) {
  .cform__pair {
    grid-template-columns: minmax(0, 1fr);
  }

  .cplace {
    flex-direction: column-reverse;
    align-items: flex-start;
  }

  .cplace__say {
    text-align: left;
  }

  .cnext__rail {
    padding-left: 38px;
  }

  .cnext__step::before {
    left: -38px;
  }
}

/* ------------------------------------------------------------------ reveal
   Armed by contact.js only when there's motion to play; without it (or
   without JS) everything simply shows. */

.contact.is-armed [data-rv] {
  opacity: 0;
  translate: 0 26px;
}

.contact.is-armed [data-rv].is-in {
  opacity: 1;
  translate: none;
  transition:
    opacity 800ms ease var(--d, 0ms),
    translate 1100ms var(--ease-out) var(--d, 0ms);
}

/* Titles don't fade: their lines rise out of their masks. */
.contact.is-armed .cstart__title[data-rv],
.contact.is-armed .csec-title[data-rv],
.contact.is-armed .cplace__title[data-rv],
.contact.is-armed .cform[data-rv],
.contact.is-armed .cstart__steps[data-rv] {
  opacity: 1;
  translate: none;
}

.contact.is-armed [data-rv] .cline > span {
  translate: 0 106%;
}

.contact.is-armed [data-rv].is-in .cline > span {
  translate: none;
  transition: translate 1150ms var(--ease-out) calc(var(--d, 0ms) + var(--l, 0) * 90ms);
}

/* The steps, and the form's blocks, follow one another. */
.contact.is-armed .cstart__steps li,
.contact.is-armed .cform > * {
  opacity: 0;
  translate: 0 18px;
}

.contact.is-armed .cstart__steps.is-in li {
  opacity: 1;
  translate: none;
  transition:
    opacity 700ms ease calc(var(--d, 0ms) + var(--s, 0) * 90ms),
    translate 1000ms var(--ease-out) calc(var(--d, 0ms) + var(--s, 0) * 90ms);
}

.contact.is-armed .cform.is-in > * {
  opacity: 1;
  translate: none;
  transition:
    opacity 700ms ease calc(var(--d, 0ms) + var(--f, 0) * 70ms),
    translate 1000ms var(--ease-out) calc(var(--d, 0ms) + var(--f, 0) * 70ms);
}

.contact.is-armed .crow::after {
  scale: 0 1;
}

.contact.is-armed .crow.is-in::after {
  scale: 1 1;
  transition: scale 1200ms var(--ease-out) calc(var(--d, 0ms) + 150ms);
}

@media (prefers-reduced-motion: reduce) {
  .contact *,
  .contact *::before,
  .contact *::after {
    animation: none !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }
}

/* Phones: the site's section rhythm (--sec-top / --sec-bot / --sec-end, tokens.css),
   so every gap between two sections reads the same. */
@media (max-width: 719px) {
  .cstart {
    padding-bottom: var(--sec-bot);
  }

  .cdirect,
  .cnext {
    padding-top: var(--sec-top);
    padding-bottom: var(--sec-bot);
  }

  .cplace {
    padding-top: var(--sec-top);
    padding-bottom: var(--sec-end);
  }
}
