/* =========================================================================
   Troutwood ask pages
   The two pages where the site stops arguing and asks for something back:
   /demo and /contact. Shared because they are the same page with a different
   question in it, and because a form that looks like two different forms on
   two adjacent pages reads as two different companies.

   Everything here is additive: tokens, primitives, the field, nav and footer
   all come from tw-system.css. Organised by section, in page order.

   Both pages put the form in the hero. Every other page on the site earns a
   full screen of type before it asks for anything, because it is still making
   the case; a reader who has arrived here has already decided, and making
   them scroll past a headline to reach the field they came to fill in is a
   toll, not an argument.
   ========================================================================= */

/* -------------------------------------------------------------------------
   01. Tokens
   ------------------------------------------------------------------------- */

:root {
  /* The one colour the design system did not need until there was a form to
     get wrong. Quoted, like every value in section 02 of tw-system.css,
     against the glow's core (#29522D) rather than the darkest ground:
       --alert  #ffb4a3   5.2:1 on the glow, 9.6:1 on --band-forest
     A saturated red measures under 3:1 there and would have to be a bigger,
     bolder thing to be legible, which is a lot of alarm for a missing
     surname. This is the same warmth as the field, turned. */
  --alert: #ffb4a3;
  --alert-line: rgba(255, 180, 163, 0.5);
  --alert-wash: rgba(255, 120, 96, 0.09);
}

/* Every state change in the panel below is an attribute toggle: the form is
   hidden when it has been sent, a conditional field is hidden until it is
   asked for, the error line is hidden until there is one. `[hidden]` is a UA
   rule at the lowest specificity, so any class here that sets `display` would
   quietly beat it and show the lot. */
[hidden] {
  display: none !important;
}

/* -------------------------------------------------------------------------
   02. The ask
   A hero that has given up being a hero: no centred measure, no full screen,
   and the form beside the argument rather than under it.
   ------------------------------------------------------------------------- */

.hero--ask {
  /* The form decides the height. On a phone that is well past a screen
     already, and on a desktop a half-empty viewport under the submit button
     is the page looking unfinished. */
  min-height: auto;
  align-items: start;
  padding-bottom: clamp(3.5rem, 7vw, 6rem);
}

.ask__grid {
  display: grid;
  gap: clamp(2.5rem, 5vw, 3.5rem);
  /* The hero centres its inner block. A form is read down the left. */
  text-align: left;
}

/* One column until the form column can hold two fields side by side without
   either of them getting narrower than a name. Below that the two halves
   stack, argument first: it is short, and it is what tells someone whether
   the form under it is worth filling in. */
@media (min-width: 64rem) {
  .ask__grid {
    grid-template-columns: minmax(0, 1fr) minmax(27rem, 30rem);
    gap: clamp(3rem, 5vw, 4.5rem);
    align-items: start;
  }

  /* The form runs past the fold; the reason for filling it in should not
     scroll away while someone is doing it. */
  .ask__brief {
    position: sticky;
    top: calc(var(--nav-h) + 2.5rem);
  }
}

.ask__title {
  margin-top: 1.25rem;
  /* Two steps down from the homepage display. The headline is no longer the
     thing on the screen worth looking at; the form is. */
  font-size: clamp(2.25rem, 1.5rem + 2.6vw, 3.5rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.04em;
}

.ask__title-accent {
  color: var(--sage);
}

.ask__sub {
  max-width: 34rem;
  margin-top: 1.5rem;
  font-size: var(--step-lead);
  line-height: 1.5;
  color: var(--text-secondary);
  text-wrap: pretty;
}

.ask__note {
  margin-top: 2rem;
  font-size: var(--step-small);
  color: var(--text-tertiary);
}

/* -------------------------------------------------------------------------
   03. The brief
   What the reader gets for the minutes they are about to spend, in the order
   it happens. Numbered on /demo, where the steps are a sequence; the same
   markup carries the routing list on /contact, where they are not, so the
   number is a modifier rather than a counter on the list itself.
   ------------------------------------------------------------------------- */

.brief {
  display: grid;
  gap: 1.5rem;
  max-width: 32rem;
  margin-top: clamp(2rem, 4vw, 2.75rem);
  padding-top: clamp(1.75rem, 3.5vw, 2.25rem);
  border-top: 1px solid var(--rule);
}

.brief__item {
  display: grid;
  grid-template-columns: 1.75rem minmax(0, 1fr);
  gap: 0.25rem 1rem;
}

/* Sage, small, and set in the same tabular figures the console uses, so a
   three-step list stays a column rather than three numbers at three widths. */
.brief__num {
  grid-row: span 2;
  font-size: var(--step-small);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
  color: var(--sage-bright);
}

.brief__item h3 {
  font-size: var(--step-body);
  line-height: 1.35;
}

.brief__item p {
  grid-column: 2;
  margin-top: 0.375rem;
  font-size: var(--step-small);
  line-height: 1.55;
  color: var(--text-secondary);
}

.brief__item a {
  color: var(--sage-bright);
}

/* The routing list on /contact is a set, not a sequence, so it gives up the
   number column rather than standing empty ones in it. */
.brief--plain .brief__item {
  grid-template-columns: minmax(0, 1fr);
}

.brief--plain .brief__item p {
  grid-column: 1;
}

/* -------------------------------------------------------------------------
   04. The panel
   The form's own surface. Same recipe as .trust__panel in tw-system.css, at
   a smaller padding: it is the one other place on the site where a block of
   content is held rather than laid on the field, and two different panels
   would read as two different systems.
   ------------------------------------------------------------------------- */

.ask__panel {
  position: relative;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  background: linear-gradient(140deg, rgba(31, 68, 48, 0.55), rgba(11, 26, 17, 0.78));
  border: 1px solid var(--rule);
  border-radius: calc(var(--radius) + 8px);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  /* Cast onto the field rather than glowing into it, so the panel reads as
     sitting in front of the page and not as a lit rectangle on it. */
  box-shadow: 0 34px 60px -34px rgba(2, 8, 4, 0.85);
}

.ask__panel-title {
  font-size: var(--step-h3);
}

.ask__panel-sub {
  margin-top: 0.5rem;
  font-size: var(--step-small);
  line-height: 1.5;
  color: var(--text-tertiary);
}

/* -------------------------------------------------------------------------
   05. Fields
   ------------------------------------------------------------------------- */

.form {
  display: grid;
  gap: 1.125rem;
  margin-top: 1.75rem;
}

/* Two fields to a row where the pair is one fact — a name, a company and the
   title held at it. Never wider than that: a row of three is a row nobody
   can fill in on a phone. */
.form__row {
  display: grid;
  gap: 1.125rem;
  grid-template-columns: 1fr;
}

@media (min-width: 30rem) {
  .form__row {
    grid-template-columns: 1fr 1fr;
  }
}

.form__field {
  display: grid;
  gap: 0.4375rem;
  /* A grid item is min-width:auto by default, which lets a long placeholder
     push a two-up row wider than its column. */
  min-width: 0;
}

.form__label {
  font-size: var(--step-small);
  font-weight: 600;
  line-height: 1.3;
  color: var(--text-secondary);
}

/* Nearly every field here is required, so the ones that are not are what
   gets marked. Marking the majority instead turns the form into a wall of
   asterisks and tells the reader nothing. */
.form__optional {
  margin-left: 0.375rem;
  font-weight: 400;
  font-size: var(--step-eyebrow);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}

/* Recessed rather than raised: a field is a hole in the panel, and sinking it
   also buys the edge below its contrast.

   The border is a hand-written value rather than --rule-strong because a
   control's own edge is held to 3:1 by WCAG 1.4.11 and the token does not
   reach it here. Measured against the two grounds it actually sits between,
   the panel (about #11291b once the gradient has composited) and the field's
   own fill:
     border  rgba(255,255,255,0.34)   3.0:1 on the panel, 3.3:1 on the fill
   --rule-strong, which is 0.22, measures 2.0:1 on the panel. It is the right
   value for a rule between two pieces of text and the wrong one for the edge
   of something you are meant to click into. */
.form__control {
  width: 100%;
  min-height: 46px;
  padding: 0.6875rem 0.875rem;
  font-family: inherit;
  font-size: var(--step-small);
  line-height: 1.45;
  color: var(--text-primary);
  background: rgba(4, 12, 7, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.34);
  border-radius: 10px;
  /* Dark form controls, dark native select menu, dark autofill. Without it
     the browser draws its own light chrome inside a dark panel. */
  color-scheme: dark;
  transition: border-color 160ms var(--ease), background-color 160ms var(--ease);
}

.form__control::placeholder {
  color: rgba(214, 231, 219, 0.5);
}

.form__control:hover {
  border-color: rgba(255, 255, 255, 0.5);
}

/* Sage on the field's own fill is 7.3:1, so the focused edge is the loudest
   thing in the panel, which is the point. */
.form__control:focus {
  background: rgba(4, 12, 7, 0.5);
  border-color: var(--sage);
}

/* The base :focus-visible in tw-system.css sets border-radius: 3px so the
   focus ring hugs an inline link. On a control with corners of its own that
   would square them for as long as the field is focused, which reads as the
   input changing shape under the cursor. The ring is unchanged; only the
   radius is put back. */
.form__control:focus-visible {
  border-radius: 10px;
}

.form__control:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* The caret is drawn here rather than left native, because a native caret on
   a dark control is drawn in the platform's colour and lands as the one grey
   object on the page. Padding on the right keeps a long option clear of it. */
select.form__control {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 2.5rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%238fd9a3' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 4.5 6 8l3.5-3.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.875rem center;
  background-size: 12px 12px;
  cursor: pointer;
}

/* Until something is chosen the placeholder option is showing, and it is a
   prompt rather than an answer. */
select.form__control:invalid,
select.form__control[data-empty] {
  color: rgba(214, 231, 219, 0.55);
}

textarea.form__control {
  min-height: 7.5rem;
  /* Horizontal drag can only break the panel; vertical is the one people
     actually want. */
  resize: vertical;
}

.form__hint {
  font-size: var(--step-eyebrow);
  letter-spacing: 0.01em;
  line-height: 1.5;
  color: var(--text-tertiary);
}

/* ---- Invalid --------------------------------------------------------------
   Set only after a submit has been attempted, never while someone is still
   typing their email address for the first time. See tw-forms.js. */

.form__field.is-invalid .form__control {
  border-color: var(--alert-line);
  background: var(--alert-wash);
}

.form__error {
  display: flex;
  align-items: baseline;
  gap: 0.4375rem;
  font-size: var(--step-eyebrow);
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--alert);
}

/* Colour is never the only carrier: the mark is what an error looks like in
   greyscale and to anyone who cannot see the tint. */
.form__error::before {
  content: '!';
  flex: none;
  width: 1rem;
  height: 1rem;
  border: 1px solid currentColor;
  border-radius: 50%;
  font-size: 0.625rem;
  font-weight: 700;
  line-height: 0.875rem;
  text-align: center;
}

/* ---- Honeypot -------------------------------------------------------------
   Off-screen rather than display:none. A field that is not rendered at all is
   the first thing a competent bot skips; a field that is in the layer tree,
   labelled, and simply not where anyone can see it gets filled in. Hidden
   from assistive technology by aria-hidden and taken out of the tab order by
   tabindex on the input itself, so nobody using the page by keyboard or
   screen reader can land in it by accident. */
.form__trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* -------------------------------------------------------------------------
   06. Captcha, status and submit
   ------------------------------------------------------------------------- */

/* hCaptcha renders a fixed-size iframe into this box, and tw-forms.js loads it
   on first interaction rather than on page load, so the height it will take is
   reserved here. The alternative is the submit button jumping down the panel at
   the exact moment someone is reaching for it.

   303x78 at the normal size. Below 26rem the panel's inner measure is narrower
   than that and the widget would overflow it, so the script renders the compact
   one instead: 164x144, taller and narrower, which is why the reservation
   changes with it rather than being one number. The breakpoint is duplicated in
   tw-forms.js; they have to agree. */
.form__captcha {
  min-height: 78px;
}

@media (max-width: 26rem) {
  .form__captcha {
    min-height: 144px;
  }
}

/* The one message that is about the whole form rather than one field in it:
   the network failed, the captcha was refused, the service said no. */
.form__status {
  padding: 0.75rem 0.875rem;
  font-size: var(--step-small);
  line-height: 1.5;
  color: var(--alert);
  background: var(--alert-wash);
  border: 1px solid var(--alert-line);
  border-radius: 10px;
}

.form__submit {
  width: 100%;
}

/* Restores the button's corners for the same reason .form__control restores
   its 10px. */
.form__submit:focus-visible {
  border-radius: var(--radius-btn);
}

.form__submit[disabled] {
  opacity: 0.7;
  cursor: progress;
  transform: none;
}

.form__foot {
  font-size: var(--step-eyebrow);
  line-height: 1.6;
  letter-spacing: 0.01em;
  color: var(--text-tertiary);
}

.form__foot a {
  color: var(--text-secondary);
}

/* -------------------------------------------------------------------------
   07. Sent
   What the panel becomes. It replaces the form in place rather than sending
   the reader to a thank-you page: the answer to "did that work" belongs where
   the question was asked, and a redirect loses anyone who wanted to read the
   page they were on.
   ------------------------------------------------------------------------- */

.form__done {
  display: grid;
  justify-items: start;
  gap: 0.875rem;
  /* Roughly the height of the form it replaces, so the page does not collapse
     upward underneath the reader at the moment they submit. */
  min-height: 16rem;
  align-content: center;
}

.form__done-mark {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  color: var(--sage-bright);
  border: 1px solid var(--sage);
  border-radius: 50%;
  box-shadow: 0 0 24px var(--accent-glow);
}

.form__done h2 {
  font-size: var(--step-h3);
}

.form__done p {
  font-size: var(--step-small);
  line-height: 1.6;
  color: var(--text-secondary);
}

.form__done a {
  color: var(--sage-bright);
}

/* -------------------------------------------------------------------------
   08. Reduced motion
   ------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .form__control {
    transition: none;
  }
}
