/* ---------------------------------------------------------------------------
   The contact section, and it is a fourth stylesheet for the reason there is a
   second and a third: `styles.css` is about ONE material — a one-bit ribbon and
   the chrome that has to stay legible over it — `styles.home.css` is about a
   page, `styles.about.css` is about a second page on the same machine, and this
   is about a FORM. Nothing else in the piece has an input in it, a label, a
   caret, an error, or a control that has to keep working while somebody's
   thumb is over the half of the screen a keyboard just took.

   The tokens are shared, because they are declared on `:root` over there. Two
   of them do all the work in here and there is no third: `--paper` is the
   ground, `--ink` is what is printed on it, and the dial in the crown swaps the
   pair. Every surface below is one or the other, which is why this section —
   alone among the four — needs no `setInvert` at all. It turns over for free.
--------------------------------------------------------------------------- */

/* The section is `#contact` and the class is `.talk`, because `.contact` is
   already the pill in the crown that opens it. Two different objects, and
   naming them the same thing is how a stylesheet starts lying. */
.talk {
  position: fixed;
  inset: 0;
  z-index: 5;
  background: var(--paper);
  color: var(--ink);
  opacity: 0;
  visibility: hidden;

  /* THE ONE SECTION IN THE PIECE THAT SCROLLS NATIVELY. The landing and About
     are a transformed track and own the wheel; that is right for a page which
     is read and wrong for a page which is typed into — see the head of
     `contact/section.js`. `contain` is what stops the scroll handing off to the
     ribbon underneath when this reaches its end. */
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;

  transition:
    opacity 0.5s var(--ease-out),
    visibility 0s linear 0.5s,
    --done 0.55s var(--ease-out);

  /* How full the brief is, 0..1. Written from `section.js` and read by exactly
     one thing: the last word of the headline. Registered in the same file, so
     it interpolates rather than jumping between two levels. */
  --done: 0;

  /* The type scale. Its own, and not the landing's: that one is set for a page
     read at arm's length in one pass, and this is a headline at the size of a
     door over a column of controls read at thirty centimetres.

     The display size is a third larger than it was, on both layouts. It is the
     only thing on this screen that is allowed to be big, and it earned the room
     twice over: two paragraphs came out from under it, and on a wide window the
     form moved into a second column. */
  --t-display: clamp(3.6rem, 14vw, 11rem);
  --t-lead: clamp(1.02rem, 1.35vw, 1.42rem);
  --t-body: clamp(0.94rem, 1.02vw, 1.1rem);
  --t-chip: clamp(0.82rem, 0.95vw, 1rem);
  /* THE MEASURE, and it is one number for every width this section is ever
     given. It was 1120px, which is a spread's width — right while the headline
     and the form stood in two columns and far too wide for either of them on
     its own. A single column of controls at 1120px is a form whose labels are
     a thumb's length from the boxes they name.

     44em is about as wide as a line of this type can be and still be taken in
     one movement, and it is the same width the fields, the chips, the menu and
     the button all stop at — which is what makes the column read as one object
     rather than as a stack of them. */
  --col: min(44em, 100% - var(--pad) * 2);
}

body.is-contact .talk {
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}

/* The defs live in the document because `url(#id)` resolves in the referencing
   element's tree. They must take no space and paint nothing. */
.talk__filter {
  position: absolute;
  width: 0;
  height: 0;
  pointer-events: none;
}

.talk__page {
  width: var(--col);
  margin: 0 auto;
  padding-top: clamp(118px, 19vh, 230px);
  padding-bottom: clamp(96px, 16vh, 190px);
}

/* --- the filing ------------------------------------------------------------
   The site's name is the top left corner in every section and what you are
   looking at goes under it. Same object as the column's, same classes' shape,
   and `fixed` rather than `absolute` because this layer scrolls and a filing
   that scrolls away is a filing for the part of the page it left. */
.talk__head {
  position: fixed;
  top: calc(var(--pad-edge) + 2.9em);
  left: var(--pad-edge);
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.55em;
  pointer-events: none;
  font-size: var(--t-micro);
  font-weight: 500;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.talk__kicker {
  opacity: 0.45;
}

/* The one number this section owes anybody, set the way the ribbon sets
   `01 / 23`. A promise printed as a counter is a promise with a unit on it. */
.talk__count {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.14em;
}

.talk__count em {
  font-style: normal;
  margin: 0 0.45em;
  opacity: 0.3;
}

.talk__count i:last-child {
  font-style: normal;
  opacity: 0.32;
}

/* Where you are down the form. The index's rule stood on its end, which is what
   the column and the landing both use — the same two pixels saying the same
   thing in every section that is longer than a screen. */
.talk__rail {
  position: fixed;
  top: 24vh;
  bottom: 24vh;
  right: calc(var(--pad) * 0.72);
  z-index: 6;
  width: var(--hair);
  pointer-events: none;
}

/* The track is drawn by the rail's own ::before rather than by the rail, so the
   bar inside it can be at full strength: a child's opacity multiplies its
   parent's, and a tenth-strength rail can only ever hold a tenth-strength bar. */
.talk__rail::before {
  content: "";
  position: absolute;
  inset: 0;
  background: currentColor;
  opacity: 0.12;
}

.talk__rail i {
  position: absolute;
  inset: 0 0 auto 0;
  display: block;
  height: calc(var(--p, 0) * 100%);
  background: currentColor;
  opacity: 0.85;
}

/* --- the headline ----------------------------------------------------------
   One sentence, one weight, one colour, and it is the only thing in the left
   half of the screen.

   The last word used to be set TWICE — an outline, and a solid copy clipped up
   from the foot by `--done` so the sentence filled as the brief did. It was the
   cleverest thing on the page and it cost the headline the one property a
   headline on a contact screen has to have: being unambiguous. Half a word in
   outline reads as half a word. The reader whose eye lands on it first is told
   the page is unfinished rather than that they are, and a stroked outline
   beside a solid one is two typefaces in a three-word sentence.

   Solid ink, and thirty per cent bigger for the room that leaves. `--done` is
   still written every time the form changes and it still drives the rule down
   the right edge; what is gone is only its second readout.

   The face the works are named in, not the one the furniture is set in — the
   same call the opened project's title and the line over the run make. The
   family ships Regular and Ultralight and nothing else, so this is 400: asking
   for 900 here lands on a synthesised bold, which is the browser smearing a
   face sideways and calling it a weight. */
.talk__display {
  margin: 0;
  font-family: "PP Supply Sans", "Satoshi", system-ui, sans-serif;
  font-size: var(--t-display);
  font-weight: 400;
  line-height: 0.92;
  letter-spacing: -0.026em;
  text-wrap: balance;
  color: var(--ink);
}

/* The three pieces are still three elements — the middle word is set apart from
   the two beside it and always was — but nothing distinguishes them any more
   except that the middle one may break to its own line. */
.talk__word,
.talk__stop {
  color: inherit;
}

/* --- the other way through --------------------------------------------------
   A reader who does not want to fill in a form has to be given somewhere to go.
   It used to be a clause in the middle of the second paragraph; both paragraphs
   are gone and this is what was worth keeping out of them. */
.talk__alt {
  margin: clamp(20px, 3.4vh, 40px) 0 0;
  font-size: var(--t-body);
  letter-spacing: 0.01em;
}

.talk__mail {
  color: inherit;
  text-decoration: none;
  border-bottom: var(--hair) solid currentColor;
  padding-bottom: 0.12em;
  opacity: 0.62;
  transition: opacity 0.3s var(--ease-out);
}

.talk__mail:hover,
.talk__mail:focus-visible {
  opacity: 1;
}

/* --- the written fields ---------------------------------------------------- */

.talk__form {
  margin-top: clamp(52px, 9vh, 120px);
}

.talk__fields {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(30px, 4.4vh, 58px) clamp(20px, 2.4vw, 40px);
}

.field {
  position: relative;
  grid-column: span 12;
  display: block;
  cursor: text;
}

.field--half {
  grid-column: span 6;
}


/* --- the pickers -----------------------------------------------------------
   See the head of `contact/pick.js` for what the goo actually is. What is in
   here is only the three rules that make it work at all:

   1. THE STAGE IS ISOLATED AND PAINTS ITS OWN GROUND. The labels ride
      `mix-blend-mode: difference`, and a blend inside an isolated group blends
      with what is painted UNDER it inside that group. Without a ground of its
      own the group starts transparent and the difference returns the source
      unchanged — white type on white paper.
   2. THE LABELS ARE WHITE, ALWAYS. Difference against the paper returns the
      paper's opposite; against a body it returns the body's opposite, which is
      the paper again. Both themes, both states, and every frame of a body
      travelling under a word — one declaration, no script.
   3. THE BODIES ARE `--ink`. Not white: on a turned-over sheet they are black,
      and the threshold does not care which — it only ever raises alpha. */
.pick {
  margin-top: clamp(46px, 7vh, 96px);
}

.pick__head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.4em 1em;
  margin-bottom: clamp(16px, 2.2vh, 26px);
}

.pick__title {
  font-size: var(--t-lead);
  font-weight: 500;
}

/* Sentence case, for the reason written over `.field__label`: this sits in the
   form beside the questions, and it is the studio asking rather than the
   machine labelling. */
.pick__hint {
  font-size: var(--t-body);
  letter-spacing: 0.005em;
  text-transform: none;
  opacity: 0.42;
}

.pick__stage {
  position: relative;
  isolation: isolate;
  background: var(--paper);
  border-radius: 999px;
}

.pick__stage--blobs {
  /* Not a pill: eleven chips wrap into a block, and a 999px radius on a block
     is a lozenge. The ground only has to exist, not to be a shape. */
  border-radius: 26px;
  margin-inline: -6px;
  padding: 6px;
}

.pick__goo {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.pick__blob {
  position: absolute;
  display: block;
  transform: scale(var(--s, 0));
  transform-origin: 50% 50%;
  transition: transform 0.52s var(--ease-pop);
  will-change: transform;
}

.pick__skin {
  position: absolute;
  inset: 0;
  display: block;
  border-radius: 999px;
  background: var(--ink);
}

/* Every body breathes on its own clock — see `#blobs` in pick.js for why the
   periods are all different. It is under the threshold, so what is actually
   seen is not the body changing size: it is the NECK between two neighbours
   thickening and thinning, which is the ribbon's own ligament at the size of a
   chip. */
.pick__stage--blobs .pick__skin {
  animation: pick-breathe var(--wob-t, 4s) var(--wob-d, 0s) ease-in-out infinite;
}

@keyframes pick-breathe {
  0%,
  100% {
    transform: scale(1, 1);
  }
  50% {
    transform: scale(1.012, 1.075);
  }
}

/* The body that trails the travelling one. Slightly proud of it, so what leaves
   the segment being abandoned is a drip rather than an edge. */
.pick__blob--lag .pick__skin {
  transform: scale(0.94, 0.86);
}

.pick__stage--slider .pick__blob {
  /* The two edges get their two durations from `pick.js`, in this order. A
     transform cannot do this — it is one animation of one box and both edges
     arrive together. */
  transition-property: left, right, transform;
  transition-timing-function: var(--ease-out), var(--ease-out), var(--ease-pop);
}

.pick__row {
  position: relative;
  z-index: 1;
  /* See note 2 above. */
  mix-blend-mode: difference;
  color: #ffffff;
}

.pick__stage--blobs .pick__row {
  display: flex;
  flex-wrap: wrap;
  /* The gap is the merge distance. Wider than about 18px and two picked
     neighbours stop welding; narrower and the row reads as one bar whether one
     or six are picked. */
  gap: 10px;
}

.pick__stage--slider .pick__row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
}

.pick__opt {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.7em;
  margin: 0;
  padding: 0.86em 1.25em;
  border: 0;
  border-radius: 999px;
  background: none;
  color: inherit;
  font: inherit;
  font-size: var(--t-chip);
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.4s var(--ease-pop-soft);
}

.pick__opt:hover {
  transform: translateY(-1px);
}

.pick__opt:active {
  transform: scale(0.97);
}

.pick__opt:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* The separators in the segmented row, and only between segments. Under
   difference these are the paper's opposite over the ground and the body's
   opposite over the body, exactly like the labels — so the one that runs
   through the travelling body does not disappear into it. */
.pick__stage--slider .pick__opt + .pick__opt::before {
  content: "";
  position: absolute;
  left: 0;
  top: 26%;
  bottom: 26%;
  width: var(--hair);
  background: currentColor;
  opacity: 0.22;
}

.pick__name {
  display: block;
}

/* A plus that turns into a cross. Two rules and not a glyph, which is how this
   piece draws every other mark it has — and it is the chip saying which way
   pressing it goes rather than a tick reporting what it already did. */
.pick__mark {
  position: relative;
  width: 9px;
  height: 9px;
  flex: none;
  opacity: 0.5;
  transform: rotate(0deg);
  transition:
    transform 0.45s var(--ease-pop),
    opacity 0.3s var(--ease-out);
}

.pick__mark i {
  position: absolute;
  background: currentColor;
}

.pick__mark i:first-child {
  left: 0;
  right: 0;
  top: 50%;
  height: var(--hair);
  transform: translateY(-50%);
}

.pick__mark i:last-child {
  top: 0;
  bottom: 0;
  left: 50%;
  width: var(--hair);
  transform: translateX(-50%);
}

.pick__opt.is-on .pick__mark {
  transform: rotate(135deg);
  opacity: 0.85;
}

.pick__stage--slider .pick__mark {
  display: none;
}

/* --- linear chips ----------------------------------------------------------
   The goo is off, and this is what replaced it.

   What the metaballs were FOR was a picked set reading as one body: press three
   neighbours and they weld, and the row says "these, together" in a shape
   instead of in three ticks. It is the ribbon's own ligament at the size of a
   chip and it is the best thing in this section.

   It is also the wrong instrument for the job it was doing. A blob under a word
   is a SURFACE, and a surface has no edge you can point at — the reader is
   asked to find eleven pressable things inside one soft mass, at a size where
   the mass is mostly gaps. The row read as an illustration of a choice rather
   than as the choice. Everything above this line — the stage, the goo layer,
   the bodies, the breathing — is left in place and left commented, because it
   is worth reading and because the JS still builds it; what changes is that it
   paints nothing and the OUTLINE is what is seen.

   One box per option, one hairline, and picked is the box filled with ink. It
   is the same one-bit vocabulary the rest of the sheet is drawn in, and it is
   the only state a chip can be in that nobody has to be taught. */
.pick__goo {
  display: none;
}

/* The stage was a ground for a blend and a ground for the bodies. Neither is
   left, so it is a plain box: no isolation, no paper of its own, no radius. */
.pick__stage {
  isolation: auto;
  background: none;
  border-radius: 0;
}

.pick__stage--blobs {
  border-radius: 0;
  margin-inline: 0;
  padding: 0;
}

/* Difference goes with the bodies it was written for. There is nothing
   travelling under these labels any more, so they are simply ink. */
.pick__row {
  mix-blend-mode: normal;
  color: inherit;
}

.pick__stage--blobs .pick__row {
  /* No longer a merge distance — just a gap. */
  gap: clamp(6px, 0.62vw, 10px);
}

.pick__stage--slider .pick__row {
  gap: clamp(6px, 0.62vw, 10px);
}

/* A PILL, FILLED, and it replaced an outlined rectangle.

   Eleven outlined boxes in a block is eleven rectangles the eye has to parse as
   a set, on a screen that already has four fields drawn the same way. The
   change is the same one the fields made and for the same reason: the unpicked
   state is a WELL — a shade off the paper, no border — so the row reads as a
   soft field of options rather than as eleven fences, and the picked ones are
   the only hard shapes in it.

   Pill and not a 11px rectangle, because a pill is the one shape on this page
   that is not also a field: a reader glancing at the form can tell the row of
   things to PRESS from the row of things to TYPE IN without reading either.

   And it is bigger. `min-height` is the number that matters — a chip is a
   target before it is a label, and 44px is the size a thumb is. */
.pick__opt {
  min-height: 36px;
  border: var(--hair) solid transparent;
  border-radius: 999px;
  padding: 0.5em 1.05em;
  background: color-mix(in srgb, var(--ink) 5%, transparent);
  transition:
    transform 0.4s var(--ease-pop-soft),
    border-color 0.3s var(--ease-out),
    background-color 0.3s var(--ease-out),
    color 0.3s var(--ease-out);
}

.pick__opt:hover {
  background: color-mix(in srgb, var(--ink) 11%, transparent);
}

/* Picked. The two colours of the sheet, swapped — which is what "picked" has
   meant everywhere else in this piece for the whole of its length. */
.pick__opt.is-on {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

.pick__opt.is-on:hover {
  background: color-mix(in srgb, var(--ink) 84%, var(--paper));
  border-color: color-mix(in srgb, var(--ink) 84%, var(--paper));
}

/* The mark is a state, so it carries the weight of one. At a fifth it was a
   detail on a chip; picked, it is the thing that says so. */
.pick__opt .pick__mark {
  opacity: 0.38;
}

.pick__opt:hover .pick__mark {
  opacity: 0.62;
}

.pick__opt.is-on .pick__mark {
  opacity: 1;
}


/* The segmented row has edges of its own now. A separator between two boxes is
   a third line where two already meet. */
.pick__stage--slider .pick__opt + .pick__opt::before {
  display: none;
}

/* What the section says back once a band has been pressed. One line, and it is
   the only opinion in here. */
.pick__note {
  min-height: 1.5em;
  margin: 1.1em 0 0;
  font-size: var(--t-body);
  opacity: 0;
  transform: translateY(4px);
  transition:
    opacity 0.42s var(--ease-out),
    transform 0.42s var(--ease-out);
}

.pick__note.is-on {
  opacity: 0.55;
  transform: none;
}

/* --- the way it is sent -----------------------------------------------------
   The brief line is gone from the markup — see the note where it used to be
   built in `section.js` — so the button follows the last question directly.

   A COLUMN, not a row. The button is the measure wide, which is the one thing
   that makes a form feel finished: every control above it is the width of the
   column, and a send button sized to its own label is the last object on the
   page disagreeing with all of them. Anything it has to say goes under it. */
.talk__send {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.8em;
  margin-top: clamp(20px, 2.6vh, 30px);
}

/* The one loud object on the page, and it is allowed to be: everything above it
   is asking, and this is the thing that answers. Its own tokens are set here
   rather than in the component, so the alloy's plate and label are the sheet's
   own two colours and turn over with it. */
.talk__send vs-button-chrome {
  width: 100%;
  --ctrl-h-lg: clamp(52px, 5.2vw, 62px);
  --ctrl-fs-lg: var(--t-body);
  --ctrl-px-lg: clamp(28px, 3.2vw, 44px);
  --chrome-fill: var(--ink);
  --chrome-fill-ink: var(--paper);
  --inp-text: var(--ink);
  --inp-accent: var(--ink);
  font-family: inherit;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.talk__note {
  max-width: 34ch;
  margin: 0;
  font-size: var(--t-micro);
  line-height: 1.5;
  opacity: 0.4;
  transition: opacity 0.4s var(--ease-out);
}

.talk__note:empty {
  display: none;
}

.talk__note.is-sent {
  opacity: 0.85;
}

/* --- the way out ------------------------------------------------------------
   There are three, and none of them is a glass pill at the foot of the screen:
   the wordmark, the five words at the head of the sheet with the one you are on
   lit, and Esc. The foot of THIS screen is the button that sends the brief, and
   a pill parked over it is a reader choosing between "send" and "leave" at the
   same coordinates. */

/* --- the shell, while this section is up ------------------------------------
   The same trade every other section makes: the readings OF the ribbon step
   aside — the sentence over it, the fusion, the count, the filing plates, the
   cursor and its label — and the shell stays, because walking into a section is
   not leaving the site. */
body.is-contact .creed,
body.is-contact .lockup__slot,
body.is-contact .gauge,
body.is-contact .plates,
body.is-contact .probe,
body.is-contact .tag {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.32s var(--ease-out);
}

/* The shell, and the panes it is read through. This section is a full-bleed
   ground at `5`, so the panes have to come up with the shell or the correction
   sits under the thing it is correcting — see `site/chrome-contrast.js`.

   The glass EDGE is deliberately not in this list, for the reason the note
   below already gives: the foot of this screen is a button. */
body.is-contact .chrome,
body.is-contact .crown,
body.is-contact .chromeglass {
  z-index: 6;
}

/* There was a rule here taking the glass edge off screen for this section: the
   foot of this screen is a button somebody has to be able to read, and a lens
   over a control is a control you cannot trust. The edge is unwired for the
   whole site now — see the note where `edge` used to be declared in `main.js` —
   so the rule had nothing left to hide and went with it. */

/* The pill in the crown is the way IN to this section, so while you are in it
   the pill is a control pointing at the screen it is printed on. It stays
   visible — its shape is part of the corner — and stops being pressable. */
body.is-contact .contact {
  /* At half, and it was at three tenths. The rule's own sentence says the pill
     STAYS VISIBLE because its shape is part of the corner, and 0.3 on a rim
     that is already a hairline of alloy is not a shape, it is a smudge — the
     corner read as having lost a control rather than as having one that is
     already answered. Half is unmistakably a step down from the pill on every
     other screen and still a pill. */
  opacity: 0.5;
  pointer-events: none;
}

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

@media (max-width: 820px) {
  .talk__page {
    padding-top: clamp(104px, 16vh, 170px);
  }

  .field--half {
    grid-column: span 12;
  }

  /* Five bands do not fit on one line at this width, and a segmented row that
     is scrolled sideways is a row half of whose options nobody ever sees. Two
     columns, and the body's travel between rows is a drop falling rather than
     a bar sliding — which the lag was already built for. */
  .pick__stage--slider .pick__row {
    grid-auto-flow: row;
    grid-template-columns: 1fr 1fr;
  }

  .pick__stage--slider .pick__opt + .pick__opt::before {
    display: none;
  }

  .talk__rail {
    display: none;
  }
}

@media (max-width: 520px) {
  .pick__stage--blobs .pick__row {
    gap: 8px;
  }

  .pick__opt {
    padding: 0.78em 1.05em;
  }
}

/* --- without motion ---------------------------------------------------------
   The STATES stay — a picked chip is information. Only the travel goes.

   The headline's own animation used to be in this list: the word filled from
   the foot up on a level that sloshed. Both the fill and the slosh are gone —
   see the note over `.talk__display` — so what is left here is the chips. */
@media (prefers-reduced-motion: reduce) {
  .talk,
  .talk__mail,
  .field__rule::after,
  .field__tick,
  .field__label,
  .pick__opt,
  .pick__blob,
  .pick__mark,
  .pick__note,
  .talk__note {
    transition: none;
  }

  .pick__stage--blobs .pick__skin {
    animation: none;
  }
}


/* --- one screen, one column ------------------------------------------------
   The section was a SPREAD: the headline in a left column at the size of a
   door, the form in a right one, the two of them filling a laptop without a
   scroll. The argument for it was that a screen is wider than it is tall and a
   single centred measure spends the extra width on margin.

   It was the wrong trade. What the spread actually bought was room to keep
   ELEVEN chips, five bands, four fields, a live brief line and a button on one
   screen — and a screen with all of that on it at once is not a form, it is a
   dashboard. The reader's eye starts at a headline on the left, jumps a
   hundred and eighteen pixels right, and then has to work out which of two
   left edges it is reading down. Nobody fills that in quickly, which is the
   only thing this screen is for.

   One column, and the headline sits ON it rather than beside it. One axis, one
   left edge, one order: the invitation, then the questions, then the button.
   The width is a MEASURE and not a share of the viewport — 44em is about as
   wide as a line of this type can be and still be scanned in one movement —
   so on a very large screen the form does not grow into a billboard, it just
   sits in more air. That is what "it breathes" means at 2560px.

   The scroll comes back and it is worth what it costs. The five bands are one
   select now and the brief line is gone, so what is left above the button is
   four fields, a row of chips and a menu — which is most of a screen on a
   laptop and all of one the moment the reader starts answering.

   Gated on both axes, the way the spread was: below 1040 wide or 640 tall the
   base rules above already say the same thing in a narrower measure. */
@media (min-width: 1040px) and (min-height: 640px) {
  .talk {
    /* The headline is the one thing here allowed to be large. It is no longer
       paying for a second column, so it is set from the measure it stands on
       rather than from the viewport — a display size that keeps growing after
       the column beneath it has stopped is a headline that detaches from its
       own page. */
    --t-display: clamp(2.6rem, 5.2vw, 4.2rem);
    --t-lead: clamp(0.86rem, 0.98vw, 1.02rem);
    --t-body: clamp(0.82rem, 0.9vw, 0.96rem);
    --t-chip: clamp(0.76rem, 0.84vw, 0.9rem);
  }

  .talk__page {
    /* The measure. `min()` and not a clamp against the viewport: the column is
       a fixed reading width that stops growing, and the second term is only
       there so it still has margins on a narrow window. */
    width: min(44em, 100% - var(--pad) * 2);
    /* Tuned so the whole form lands inside a laptop screen without the reader
       having to go looking for the button. It does not have to FIT — the
       section scrolls natively and always did — but a send button that is
       never on screen at the same time as the last question is a form that
       feels longer than it is. */
    padding-top: clamp(88px, 10.5vh, 138px);
    padding-bottom: clamp(48px, 8vh, 96px);
    text-align: left;
  }

  .talk__display {
    /* No balancing on a left-aligned measure. `balance` exists to stop the last
       line of a centred headline being one orphaned word; here it was pulling
       "word." up and back down as the window moved. */
    text-wrap: pretty;
  }

  /* --- the ask, over the answering ----------------------------------------
     The gap between the headline and the first label is the largest piece of
     air on the page, and it is doing the job the second column used to: it is
     what separates the sentence that invites from the machine that collects.
     Anything smaller and the headline reads as this form's first label. */
  .talk__form {
    margin-top: clamp(26px, 3.2vh, 42px);
  }

  .talk__fields {
    gap: clamp(13px, 1.7vh, 20px) clamp(14px, 1.6vw, 24px);
  }

  /* A name across the measure, the address and the number sharing a line, the
     message across the measure again. Three rows, and the two that share are
     the two that are short — a phone number in a full-measure box is a box
     five times the width of the thing going into it. */
  .field {
    grid-column: span 12;
  }

  .field--half {
    grid-column: span 6;
  }

  .field--tall {
    grid-column: span 12;
  }

  /* An explicit height, not a minimum. The element carries `rows="4"` for the
     no-CSS case and `rows` sets the box's own height, so a `min-height` under
     it changes nothing. */
  .field--tall .field__input {
    height: clamp(70px, 7.6vh, 92px);
    min-height: 0;
    resize: none;
  }

  /* --- the pickers --------------------------------------------------------
     The same air between question blocks as between fields, plus a little —
     these two are a different KIND of question from the ones above them and
     the gap is the only thing that says so. */
  .talk .pick {
    margin-top: clamp(20px, 2.6vh, 32px);
    text-align: left;
  }

  .pick__head {
    justify-content: flex-start;
    margin-bottom: clamp(8px, 1.2vh, 13px);
  }

  .pick__stage--blobs .pick__row {
    justify-content: flex-start;
    gap: 8px;
  }

  .pick__note {
    margin-top: 0.9em;
    min-height: 1.3em;
  }
}

/* ===========================================================================
   THE FORM, REDRAWN — closed boxes, a run of cards, and one address at the foot

   Everything above this line is the section as it was built and every argument
   in it is still worth reading. What follows is the layer that changed five
   things about it, and each of them is written where it happens:

     1. THE SENTENCE IS THE PAGE'S, NOT THE COLUMN'S. `SAY THE WORD.` is
        centred and a fifth larger. It is the invitation; the form is the
        machine, and the two of them sharing a left edge made the headline read
        as the first label.
     2. THE CONTROLS ARE CLOSED PILLS. A rule under a placeholder says where
        the text will land and not where the field begins or ends. Nine of them
        down a page is nine sentences with underscores.
     3. THE LABELS MOVED INSIDE. Four labels standing above four boxes is four
        rows of a screen whose whole problem is the distance to the button.
     4. THE ELEVEN CHIPS ARE A RUN. They wrapped into four rows; they are one
        row now, four and a half cards wide, and what is off the end is faded
        into the sheet rather than cut off it.
     5. THE ADDRESS IS AT THE FOOT. It is the way out, not part of the ask, and
        it sits on the same line as the marks for everywhere else this studio
        is — which is exactly what it is.
   =========================================================================== */

.talk {
  /* The control scale, and it is one set of numbers for the fields, the menu
     and the cards. Three controls that agree on a height and a side padding
     read as one instrument; three that each pick their own read as a form
     assembled out of parts. */
  --ctrl-h: clamp(46px, 4.4vh, 54px);
  --ctrl-px: clamp(16px, 1.5vw, 22px);
  /* The run's gap, and the fade over its ends. */
  --card-gap: clamp(8px, 0.9vw, 12px);
  --card-fade: clamp(30px, 5vw, 68px);
}

/* --- 1. the invitation ------------------------------------------------------
   Centred, and a fifth larger than it was. It is the only thing on the screen
   that is not a control and the only one allowed to be big, and centring it is
   what separates it from the column of questions underneath: the eye reads a
   sentence across the middle of the sheet, then drops onto a left edge and
   starts answering. Two left edges, one under the other, is one object with a
   heading — which is what it used to look like. */
.talk__hero {
  text-align: center;
}

.talk__display {
  font-size: calc(var(--t-display) * 1.2);
  /* Balanced, because it is centred: `pretty` only protects the last line, and
     a centred headline breaking two-and-one is a headline with an orphan in the
     middle of the sheet. */
  text-wrap: balance;
}

/* --- the measure, twice ----------------------------------------------------
   The headline gets the column; the FORM gets less. A field is read at the
   distance of a thumb and a headline at the distance of a room, and a name box
   as wide as a display line is a box five times the width of the thing going
   into it. The form is centred inside the column so the two share an axis
   rather than an edge. */
.talk__form {
  width: min(38em, 100%);
  margin-inline: auto;
  text-align: left;
}

/* --- 2 + 3. the written fields ---------------------------------------------
   A CLOSED PILL with the label inside it.

   The rule this replaced was the right instinct — the sheet draws marks, not
   containers — and the wrong control to have it on. A line under a field tells
   you where the writing lands; it does not tell you where the field STARTS, and
   three of them side by side are three underscored sentences rather than three
   things to type into. The pill says the whole of it in one shape, and it is
   the same shape as the cards and the menu, so the page has one radius.

   The height is bought back from the labels: they were a row of type each and
   they are now the field's own content until there is something in it. */
.talk__fields {
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(12px, 1.7vh, 20px) clamp(10px, 1.1vw, 16px);
}

/* Three on one line. Name, address and number are the three short answers on
   the page and they were taking three rows between them — the message is the
   only one of the four that needs the measure. */
.field {
  grid-column: span 4;
}

.field--half {
  grid-column: span 4;
}

.field--tall {
  grid-column: span 12;
}


/* --- 4. the run ------------------------------------------------------------
   ONE ROW, FOUR AND A HALF CARDS WIDE.

   Eleven pills wrapped into four rows of a block. Every argument for that
   layout is true — nothing is hidden, no gesture is needed, it is the honest
   thing — and it cost four rows of a screen whose only problem is the distance
   between the first question and the button that sends the answers. It also
   read as a paragraph of buttons: no order, no count, and no way to tell at a
   glance how many there were without counting them.

   A run says both. The half card at the right edge is not a mistake in the
   arithmetic — it is the row's own sentence: THERE ARE MORE OF THESE. A row
   that ends exactly on a card edge looks finished, and a reader who thinks a
   list is finished never scrolls it. The `4.5` in the width below is the whole
   design of this control.

   It is still eleven independent presses and it is still every one of them
   reachable by keyboard: Tab walks the cards and the browser scrolls each one
   into view on its own. */
.pick__stage--blobs {
  position: relative;
  isolation: auto;
}

.pick__stage--blobs .pick__row {
  display: grid;
  grid-auto-flow: column;
  /* Four and a half. The four gaps are the ones BETWEEN the visible cards. */
  grid-auto-columns: calc((100% - var(--card-gap) * 4) / 4.5);
  gap: var(--card-gap);
  overflow-x: auto;
  overflow-y: hidden;
  /* The section under this is the only natively scrolling one in the piece, and
     a run that hands its overscroll upward would drag the whole form sideways
     at the end of every swipe. */
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  /* Room for the cards' own focus ring, which is drawn outside their box —
     VERTICALLY ONLY, and that is a bug fix rather than a preference. Padding on
     the inline axis is inside the scrollport, so `scroll-snap-align: start`
     snaps to the padding edge and a run at its very start sits at scrollLeft 3
     rather than 0; and the matching negative margin pushed the row three pixels
     out past the stage on both sides, where the fades — which are the stage's
     own pseudo-elements — could not cover it. What showed for it was a sliver of
     card standing proud of the fade at each end: the line down the left and
     right corners. No inline padding, no sliver. */
  padding-block: 4px;
  margin-block: -4px;
  touch-action: pan-x;
  /* The ends are drawn by the two fades below, and a native scrollbar under a
     row of cards is a second, uglier statement of the same thing. */
  scrollbar-width: none;
}

.pick__stage--blobs .pick__row::-webkit-scrollbar {
  display: none;
}

/* THE TWO ENDS, FADED INTO THE SHEET.
   Not a mask: a mask cannot be transitioned without registering a length, and
   these have to go out when there is nothing behind them. Two gradients TO THE
   PAPER, which is black on a turned-over sheet and white on the right way up —
   the fade is the sheet closing over the run, in whichever colour the sheet
   currently is. */
.pick__stage--blobs::before,
.pick__stage--blobs::after {
  content: "";
  position: absolute;
  z-index: 2;
  /* Past the stage's own edges on all four sides. The row is padded on the
     block axis so a focused card's ring is not clipped, which makes it four
     pixels taller than the box these are measured against — and a fade that
     stops at the box leaves a corner of card showing above and below it. That
     was the line at each end. */
  top: -5px;
  bottom: -5px;
  width: calc(var(--card-fade) + 2px);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s var(--ease-out);
}

/* Solid for the first third and then out. At a tenth the sheet only really
   covered the six pixels nearest the edge, so the card underneath was still
   legible through the fade — which reads as a rendering fault rather than as
   the run continuing. */
.pick__stage--blobs::before {
  left: -1px;
  background: linear-gradient(to right, var(--paper) 34%, transparent 100%);
}

.pick__stage--blobs::after {
  right: -1px;
  background: linear-gradient(to left, var(--paper) 34%, transparent 100%);
}

/* Only while there is something off the end in that direction. A fade over
   nothing is a row that looks like it is still hiding something. */
.pick__stage--blobs.is-run:not(.at-start)::before,
.pick__stage--blobs.is-run:not(.at-end)::after {
  opacity: 1;
}

.pick__stage--blobs.is-dragging {
  cursor: grabbing;
}

.pick__stage--blobs.is-dragging .pick__opt {
  /* A card that lifts under a pointer that is dragging the row is a card that
     looks pressable at the exact moment it is not. */
  cursor: grabbing;
  transform: none;
}

/* A CARD. Same rule, same well and the same radius family as the fields — and a
   different aspect, because it is a thing to press and not a thing to type in.

   Three parts: the catalog's own two digits at the head, the discipline at the
   foot, and the plus in the corner that says which way pressing it goes. The
   digits are the reason this reads as a run at all: 01 … 11 is a set with a
   length, and a reader who can see 04 knows there are at least four more behind
   it. */
.pick__stage--blobs .pick__opt {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-rows: auto 1fr;
  gap: 0.5em;
  min-height: clamp(84px, 9.4vh, 104px);
  padding: 0.85em 0.95em;
  border-radius: 18px;
  scroll-snap-align: start;
  text-align: left;
  white-space: normal;
  line-height: 1.18;
}

.pick__code {
  grid-area: 1 / 1;
  font-size: 0.78em;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.12em;
  opacity: 0.4;
  transition: opacity 0.3s var(--ease-out);
}

.pick__stage--blobs .pick__mark {
  grid-area: 1 / 2;
  justify-self: end;
  align-self: start;
}

.pick__stage--blobs .pick__name {
  grid-area: 2 / 1 / 3 / 3;
  align-self: end;
  overflow-wrap: break-word;
}

.pick__opt.is-on .pick__code {
  opacity: 0.62;
}

/* A pressed card does not lift — it is in a row that scrolls, and a box that
   moves up under the pointer while the row moves sideways is two motions in one
   gesture. It presses IN instead. */
.pick__stage--blobs .pick__opt:hover {
  transform: none;
}

.pick__stage--blobs .pick__opt:active {
  transform: scale(0.975);
}


/* --- 5. the address, at the foot -------------------------------------------
   It was a line under the headline, which is where it went when the two
   paragraphs around it were cut. That was the right thing to keep and the wrong
   place to keep it: it is the way OUT of the form, and a way out printed above
   the first question is an invitation to not fill it in.

   Down here it is on the same line as the marks for everywhere else this studio
   can be found — Behance, Dribbble, GitHub and the rest, in the bottom rail —
   and that is exactly what it is: one more place to reach the same two people.
   Centred on the sheet, because the middle of that rail is empty while this
   section is up (the fusion gauge steps aside for every section).

   `fixed` inside a scrolling section is deliberate and it works because `.talk`
   carries no transform: the address stays on the foot of the SCREEN while the
   form scrolls past it. */
.talk__alt {
  position: fixed;
  z-index: 7;
  left: 50%;
  bottom: var(--pad-edge);
  display: flex;
  align-items: center;
  height: clamp(26px, 2vw, 28px);
  margin: 0;
  transform: translateX(-50%);
  font-size: var(--t-micro);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.talk__mail {
  opacity: 0.5;
  border-bottom-color: currentColor;
}

/* The button is the last thing in the column and the address is fixed over the
   foot of the screen; without this the two meet at the end of the scroll. */
.talk__page {
  padding-bottom: clamp(128px, 18vh, 210px);
}

/* --- wide ------------------------------------------------------------------
   The desktop block above set the display size from the measure and pulled
   every gap in. Both still hold — what changes is that the headline is centred
   and a fifth larger, so it needs its own balance back, and the three short
   fields share a line at this width too. */
@media (min-width: 1040px) and (min-height: 640px) {
  .talk__display {
    text-wrap: balance;
  }

  .talk__form {
    margin-top: clamp(30px, 3.6vh, 46px);
  }

  .talk__fields {
    gap: clamp(12px, 1.6vh, 18px) clamp(10px, 1.1vw, 16px);
  }

  .field {
    grid-column: span 4;
  }

  .field--half {
    grid-column: span 4;
  }

  .field--tall {
    grid-column: span 12;
  }

}

/* --- narrow ----------------------------------------------------------------
   Two things go at 900: the three-on-a-line row, which at a phone's width would
   be three boxes with two letters visible in each, and the number of cards in
   the run, because 4.5 of them across 360px is a card the width of a thumb. */
@media (max-width: 900px) {
  .field,
  .field--half {
    grid-column: span 6;
  }

  .field:first-child {
    grid-column: span 12;
  }

  .field--tall {
    grid-column: span 12;
  }

  .talk__form {
    width: 100%;
  }

  .pick__stage--blobs .pick__row {
    grid-auto-columns: calc((100% - var(--card-gap) * 2) / 2.6);
  }
}

@media (max-width: 620px) {
  .field,
  .field--half,
  .field:first-child {
    grid-column: span 12;
  }

  .pick__stage--blobs .pick__row {
    grid-auto-columns: calc((100% - var(--card-gap)) / 1.75);
  }

  /* The bottom rail stacks at this width and the marks move to the left edge,
     so a fixed address centred over them would land on top of them. It goes
     back into the flow, under the headline, where it began. */
  .talk__alt {
    position: static;
    height: auto;
    margin: clamp(18px, 3vh, 34px) 0 0;
    transform: none;
    justify-content: center;
  }

  .talk__page {
    padding-bottom: clamp(96px, 16vh, 190px);
  }
}

/* --- without motion --------------------------------------------------------
   The controls answer this themselves — every one of the components carries its
   own `prefers-reduced-motion` block, and a page reaching into a shadow root to
   turn off a transition it did not write is a page that will be wrong the next
   time that component is updated. What is left here is the run's own fades. */
@media (prefers-reduced-motion: reduce) {
  .pick__stage--blobs::before,
  .pick__stage--blobs::after {
    transition: none;
  }

  .pick__stage--blobs .pick__row {
    scroll-behavior: auto;
  }
}

/* ===========================================================================
   THE CONTROLS ARE COMPONENTS — and this is the whole of what the page says
   to them

   `vs-input`, `vs-textarea` and `vs-select` are the studio's own set, dropped in
   as they ship. Not one rule below reaches inside them: a shadow root is a
   boundary, and a page that gets past it with `::part` hacks or `!important` has
   simply moved the component's stylesheet somewhere it cannot be maintained.

   What crosses the boundary is TOKENS. Every colour, radius and size those
   components paint with is a `var()` with a fallback, so declaring the same
   names out here is the supported way to dress them — and because each one is
   written in `--ink` / `--paper`, the whole set turns over with the sheet with
   no script at all. That is the same trick the rest of this section already
   runs; the components simply joined it.
   =========================================================================== */

.talk {
  /* --- the ink ------------------------------------------------------------
     NO WELL, NO FILL, NO GREY. The field is the sheet with a line drawn round
     it: on the pale sheet the inside of a control is white, on the dark one it
     is black, and the only thing that says where it begins is one hairline at a
     sixth strength. That is the piece's whole vocabulary — a mark, not a
     container — and it is the one change made to these components. */
  --inp-text: var(--ink);
  --inp-border: color-mix(in srgb, var(--ink) 16%, transparent);
  --inp-border-hover: color-mix(in srgb, var(--ink) 34%, transparent);
  --inp-accent: var(--ink);
  --inp-label: color-mix(in srgb, var(--ink) 52%, transparent);
  --inp-placeholder: color-mix(in srgb, var(--ink) 34%, transparent);
  --inp-hint: color-mix(in srgb, var(--ink) 55%, transparent);
  --inp-prefix: color-mix(in srgb, var(--ink) 55%, transparent);
  --inp-btn: color-mix(in srgb, var(--ink) 55%, transparent);
  --inp-btn-hover-bg: color-mix(in srgb, var(--ink) 8%, transparent);
  /* The three fills the components would otherwise paint. All transparent: the
     inside of a control is the sheet, in both directions it can face. */
  --inp-hover-bg: transparent;
  --inp-readonly-bg: transparent;
  --sel-fill: transparent;

  /* --- the menu -----------------------------------------------------------
     THE PAPER, and not a shade off it. The menu is the same white or the same
     black as everything else; what separates it from the form underneath is one
     hairline and the fact that it is opaque. A panel tinted a few per cent to
     "lift" it is the grey this page does not have.

     And NO SHADOW: a drop shadow is a light source, this sheet has none, and it
     was the only soft edge in the piece. The `none` has to be spelled out — the
     component's own fallback is a three-layer shadow, and a token that is
     merely absent hands it straight back. */
  --sel-menu-bg: var(--paper);
  --sel-menu-border: color-mix(in srgb, var(--ink) 22%, transparent);
  --sel-menu-shadow: none;
  --sel-opt-hover: color-mix(in srgb, var(--ink) 9%, transparent);
  --ui-accent: var(--ink);
  /* The select's own accent — the chevron, the placeholder, the tick and the
     picked row all read it. The component only declares it inside a semantic
     tone, so in the default tone it falls through to whatever the document
     hands down: without this it is the component's hardcoded `#8a8a8a`, which
     is the one grey on this page that would not turn over with the sheet.
     Seventy per cent, because a chevron at full ink is as loud as the answer
     beside it. */
  --t-accent: color-mix(in srgb, var(--ink) 70%, transparent);

  /* --- the light ----------------------------------------------------------
     The proximity glow is drawn in `rgb(var(--fx-tint) / …)`, which needs three
     CHANNELS and not a colour — so it cannot read `--ink`, and it is the one
     token here that has to be told which way up the sheet is.

     The DEFAULT is the pale sheet, because that is the side this site opens on
     and because a document served without the boot script — or a bench that
     mounts this section on its own — has no `data-sheet` to read. Defaulting to
     the dark side would mean white light on white paper in exactly the cases
     nothing is there to correct it. */
  --fx-tint: 0 0 0;
  --inp-ring: 0 0 0;

  /* --- the scale ----------------------------------------------------------
     One set of numbers for the fields, the menu and the cards. Three controls
     that agree on a height and a side padding read as one instrument; three
     that each pick their own read as a form assembled out of parts. */
  --ctrl-h-lg: clamp(46px, 4.4vh, 54px);
  --ctrl-px-lg: clamp(16px, 1.5vw, 22px);
  --ctrl-fs-lg: var(--t-lead);
  --ctrl-r-lg: 14px;

  /* The run's gap, and the fade over its ends. */
  --card-gap: clamp(8px, 0.9vw, 12px);
  --card-fade: clamp(30px, 5vw, 68px);
}

/* The light, on the turned-over sheet. `[data-sheet]` is written by the one
   switch in `index.html` on every turn of the dial — see the boot script there —
   so this is the same source of truth as `--paper` and `--ink`, read a different
   way because a channel triplet is not a colour. */
:root[data-sheet="dark"] .talk {
  --fx-tint: 255 255 255;
  --inp-ring: 255 255 255;
}

/* --- the fields in the grid -------------------------------------------------
   The components are `display: inline-flex` hosts; `block` makes them fill, and
   these are the only two things the page has any business saying about them —
   which column they stand in, and how much air is under them. */
.talk__fields {
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(16px, 2.2vh, 26px) clamp(10px, 1.1vw, 16px);
  align-items: start;
}

.field {
  grid-column: span 4;
}

.field--half {
  grid-column: span 4;
}

.field--tall {
  grid-column: span 12;
}

/* The one-line fields are pills and the message is not, so their two labels
   float to different places — that is the component's own arrangement and it is
   left alone. What is set here is only the message's height: three rows is the
   shortest box somebody will actually write a paragraph into. */
.field--tall {
  --ctrl-px-lg: clamp(16px, 1.5vw, 22px);
}

/* --- the money, in the column ---------------------------------------------- */
.money {
  display: block;
  max-width: 22em;
}

@media (max-width: 900px) {
  .field,
  .field--half {
    grid-column: span 6;
  }

  .field:first-child {
    grid-column: span 12;
  }

  .field--tall {
    grid-column: span 12;
  }
}

@media (max-width: 620px) {
  .field,
  .field--half,
  .field:first-child {
    grid-column: span 12;
  }
}
