/* Contact: centred heading, then the route map scene (demos/route-map) and a message form, headed by the direct email, that hands off to
   the visitor's mail app; on wide screens the map is on the left and the form on the right. Content reveals at the
   reading line like the sections above (core/reveal.js). The background carries the middle stretch of the page's closing gradient
   (--glow-* in tokens.css), from Us in action above to the footer below. */
.contact {
  position: relative;
  z-index: 2;
  overflow-x: clip;
  background: var(--glow-side), linear-gradient(var(--glow-1), var(--glow-2) 80%); /* levels off before the footer, which then darkens */
  padding: 64px var(--gutter) 96px;
  display: grid;
  justify-items: center;
}

/* two soft red lights drifting over the gradient (light-sway in base.css), sized by the section's height so they stay clear of its
   top and bottom edges, on a layer wider than the page so its sides never show as it moves */
.contact::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: 0 -10vw;
  pointer-events: none;
  background:
    radial-gradient(40vw 30% at 35% 55%, color-mix(in srgb, var(--glow-red) 28%, transparent), transparent),
    radial-gradient(35vw 25% at 72% 40%, color-mix(in srgb, var(--glow-red) 20%, transparent), transparent);
  animation: light-sway 28s ease-in-out infinite reverse;
}

@media (prefers-reduced-motion: reduce) {
  .contact::before { animation: none; }
}

/* the closing darkening (--dark-sweep, tokens.css) fading in from the middle of the section, reaching --dark-seam strength 21px above
   the bottom edge, then handing over to the footer's (impressum.css) over those last 20px, this one fading out as that one fades in
   above the footer (the 1px lap aside), so neither ends on the seam: two darkening edges meeting on a fraction of a pixel left a
   bright hairline there at fractional pixel ratios */
.contact::after {
  content: '';
  position: absolute;
  z-index: -1;
  inset: 0;
  pointer-events: none;
  background: var(--dark-sweep);
  mask: linear-gradient(transparent 35%, var(--dark-seam) calc(100% - 21px), rgb(0 0 0 / .45) calc(100% - 16px),
    rgb(0 0 0 / .3) calc(100% - 11px), rgb(0 0 0 / .15) calc(100% - 6px), transparent calc(100% - 1px));
}

.contact :is(h2, .contact-map, .contact-form) { transition: opacity .6s ease, translate .6s cubic-bezier(.2, .7, .2, 1); }

.contact :is(h2, .contact-map, .contact-form)[data-state="pending"] {
  opacity: 0;
  translate: 0 24px;
}

/* a jump here (the header's Contact link) reveals the map before its scene has loaded, and the poster is the reduced-motion still near
   the chase's end while the live scene opens on the run's start, so fading in over the poster showed the chase rewind: the map waits,
   hidden, until the scene draws its first frame or falls back to the poster, and the swap from poster to canvas happens unseen.
   Scrolling down, the scene loads a screen ahead and is ready by then; should it take longer than 2.5s, the poster shows anyway.
   Only once the map is revealed: an animation outranks the pending rule above, so its filled end showed the map over a section that
   was still hidden */
.contact .contact-map[data-state="visible"]:has(.contact-map-scene:not([data-state])) {
  opacity: 0;
  translate: 0 24px;
  animation: contact-map-late .6s ease 2.5s forwards;
}

@keyframes contact-map-late {
  to { opacity: 1; translate: none; }
}

.contact-stage {
  display: grid;
  gap: 56px;
  width: 100%;
  max-width: 1280px;
}

.contact h2 {
  grid-column: 1 / -1;
  margin: 0 0 16px;
  text-align: center;
  font: 800 clamp(28px, 3.4vw, 52px)/1.1 var(--font-display);
  font-synthesis: none;
  letter-spacing: -.01em;
  text-transform: uppercase;
}

/* route map: the canvas fills a box of the reference image's aspect over its poster, a still of the chase near its end on transparent
   (scripts/capture-posters.mjs); the outer box reveals, the inner one carries the demo's state. The poster shows from the first paint
   and wherever the scene can't run (fallback, no JS), and gives way to the canvas at once when the scene has drawn its first frame: the
   two show different moments of the run, so a crossfade showed two trucks; the map stays hidden until then (below) */
.contact-map { min-width: 0; }

.contact-map-scene {
  /* the fields run to the box's sides; its edges fade out so they never end in a hard line */
  --map-fade: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent),
    linear-gradient(to bottom, transparent, #000 14%, #000 86%, transparent);
  position: relative;
  aspect-ratio: 1009 / 649;
}

:is(.contact-map-canvas, .contact-map-poster img) {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  mask-image: var(--map-fade);
  mask-composite: intersect;
}

.contact-map-poster img { object-fit: cover; }

/* phones: the map fills the form's grid cell, so its fields are the form's background, and runs --map-tail past it, its edges fading
   out wide and soft (the bottom over its last 100px, less on the right, where the crossing sits) so the box never shows; the scene frames it closer, the crossing about a centimetre under the
   send button at a fixed distance from the box's bottom (MAP.narrow in demos/route-map/config.js), and plays the chase once
   (demos/route-map); the form sits above it, so its fields stay the ones that take taps */
@media (max-width: 760px) {
  .contact-stage { --map-tail: 220px; }

  .contact-map-scene {
    --map-fade: linear-gradient(to right, transparent, rgb(0 0 0 / .45) 12%, #000 26%, #000 84%, rgb(0 0 0 / .45) 93%, transparent),
      linear-gradient(to bottom, transparent, rgb(0 0 0 / .45) 7%, #000 16%, #000 calc(100% - 100px), rgb(0 0 0 / .45) calc(100% - 45px), transparent);
    aspect-ratio: auto;
    height: 100%;
    opacity: .75; /* a step back behind the form's text */
  }

  .contact-form {
    grid-area: 2 / 1;
    align-self: start;
    position: relative;
    z-index: 1;
    margin-bottom: var(--map-tail);
  }

  .contact-map { grid-area: 2 / 1; }

  /* behind the form's fields the map shows at half strength, full from just above the send button, where the chase plays */
  .contact-map-scene { mask-image: linear-gradient(rgb(0 0 0 / .5) calc(100% - var(--map-tail) - 200px), #000 calc(100% - var(--map-tail) - 120px)); }
}

.contact-map-canvas {
  touch-action: pan-y;
  opacity: 0;
}

.contact-map-scene[data-state="ready"] .contact-map-canvas { opacity: 1; }
.contact-map-scene[data-state="ready"] .contact-map-poster img { opacity: 0; }

/* block titles in the accent, like the spec group titles */
.contact h3 {
  margin: 0 0 20px;
  font: 800 12px/17px var(--font-display);
  font-synthesis: none;
  color: var(--circle-base);
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* the direct email heads the form */
.contact-or {
  margin: 0 0 8px;
  color: var(--mute);
  font-size: var(--text-detail); /* on phones the hero's labels */
  line-height: 1.6;
  text-align: center; /* on phones under the centred heading */
}

@media (min-width: 761px) {
  .contact-or {
    font-size: 17px;
    text-align: start;
  }
}

.contact-mail {
  font: 800 clamp(20px, 2vw, 28px)/1.2 var(--font-display);
  font-synthesis: none;
  color: var(--ink);
  text-decoration: none;
  overflow-wrap: anywhere;
}

.contact-form {
  display: grid;
  gap: 20px;
}

.contact-field {
  display: grid;
  gap: 8px;
  color: var(--mute);
  font-size: 14px;
}

.contact-field :is(input, textarea) {
  width: 100%;
  padding: 14px 16px;
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 16px;
  line-height: 1.4;
  transition: border-color .2s;
}

/* phones: over the map behind the form, the fields carry a dark red tint */
@media (max-width: 760px) {
  .contact-field :is(input, textarea) {
    --field-red: color-mix(in srgb, var(--glow-red) 40%, var(--bg)); /* dark red */
    background: color-mix(in srgb, var(--field-red) 95%, transparent);
    /* about 2 mm wider on a phone, overhanging the gutters evenly on both sides */
    width: calc(100% + 12px);
    margin-inline: -6px;
  }
}

.contact-field textarea { resize: vertical; min-height: 140px; }

.contact-field :is(input, textarea)::placeholder {
  color: var(--mute);
  opacity: .5;
}

.contact-field :is(input, textarea):focus-visible {
  outline: 2px solid var(--circle-base);
  outline-offset: 1px;
  border-color: var(--circle-base);
}

.contact-submit {
  justify-self: start;
  padding: 18px 40px;
  border: 0;
  border-radius: 3px;
  background: var(--btn);
  color: var(--btn-ink);
  font: 500 15px var(--font-body);
  letter-spacing: .02em;
  cursor: pointer;
  transition: background .2s;
}

.contact-submit:focus-visible {
  outline: 2px solid var(--circle-base);
  outline-offset: 2px;
}

@media (min-width: 761px) {
  .contact { padding: 120px var(--gutter); }

  .contact h2 { margin-bottom: 64px; }
}

@media (min-width: 1024px) {
  .contact-stage {
    max-width: 1680px;
    grid-template-columns: minmax(0, 3fr) minmax(320px, 2fr);
    column-gap: 72px;
    row-gap: 48px;
  }

  .contact-map {
    grid-column: 1;
    grid-row: 2;
    align-self: center;
  }

  .contact-form { grid-column: 2; }
}

/* hover-only looks, for devices that can hover: a phone keeps :hover after a tap until the next one elsewhere */
@media (hover: hover) {
  .contact-mail:hover { color: var(--circle-base); }
  .contact-field :is(input, textarea):hover:not(:focus-visible) { border-color: var(--mute); }
  .contact-submit:hover { background: var(--ink); }
}
