/* A form on the front of the site.
 *
 * Deliberately little. A form plugin that ships its own opinion about what an
 * input looks like is a form that never matches the site it is on - so this
 * sets layout and states, and leaves color, type and the shape of a control to
 * the theme.
 */

/* The form stacks: what it said, the fields, then the guard and the button.
 *
 * The columns belong to the fields rather than to the form, because the fields
 * are what gets replaced when one is sent without reloading the page. They were
 * on the form itself, with every field a direct child of it - so wrapping them
 * to make them replaceable put a plain div between the grid and the things it
 * was sizing, and the whole form collapsed into one narrow column with the
 * button beside it. The grid goes where the columns are. */
/* The gap is Forms > Inputs > Between fields, and 14px until it is set -
   which is what this was written as, so nothing moves on a site that has
   never opened that card or is running without the theme. */
.dsf-form{ display:flex; flex-direction:column; gap:var(--ds-field-gap,14px);
  position:relative }

/* Twelve columns, because twelve divides by two, three and four.
 *
 * It was two, which could only ever make a row of halves. A row of thirds on a
 * two column grid has to round, and the rounding lands on one field - so the
 * last one in every row came out a pixel narrower than its neighbors. Twelve
 * divides evenly for all three, so a row is exact whatever it is split into. */
/* Rows from Between fields, columns from Between columns - and where that
   is left at nought the theme writes nothing and the row gutter answers,
   which is what the setting says it does. */
/* The column gap is capped against the grid's own width. Eleven gaps sit
   between twelve tracks, so a gutter-sized gap on a narrow form squeezes the
   tracks to nothing and the fields are then sized by gap alone - which puts
   every one of them outside the column it belongs to. */
.dsf-fields{ display:grid;
  gap:var(--ds-field-gap,14px)
      min(var(--ds-form-col-gap, var(--ds-gutter,16px)), 4%);
  grid-template-columns:repeat(12,minmax(0,1fr)) }

/* The two things that are drawn once and have to survive a send. */
.dsf-foot{ display:flex; flex-direction:column; gap:var(--ds-field-gap,14px) }

.dsf-field{ grid-column:span 12; margin:0; min-width:0 }
.dsf-field.is-full{ grid-column:span 12 }
.dsf-field.is-half{ grid-column:span 6 }
.dsf-field.is-third{ grid-column:span 4 }
.dsf-field.is-quarter{ grid-column:span 3 }

/* Quarters are too narrow for a real control long before the page is. They
   pair up first, and everything goes to full width at the phone. */
@media (max-width:820px){
  .dsf-field.is-quarter{ grid-column:span 6 }
}

@media (max-width:600px){
  .dsf-field.is-half,
  .dsf-field.is-third,
  .dsf-field.is-quarter{ grid-column:span 12 }
}

.dsf-field label{ display:block; margin-bottom:4px; font-weight:600 }

.dsf-field input[type="text"],
.dsf-field input[type="email"],
.dsf-field input[type="tel"],
.dsf-field input[type="url"],
.dsf-field input[type="number"],
.dsf-field input[type="date"],
.dsf-field input[type="file"],
.dsf-field select,
.dsf-field textarea{ width:100%; max-width:100%; box-sizing:border-box }

/* A choice is a label with a box in it, so the words are part of the target. */
.dsf-choices{ display:flex; flex-wrap:wrap; gap:6px 18px }
.dsf-choice{ display:inline-flex; align-items:center; gap:6px; font-weight:400 }
.dsf-choice input{ margin:0; flex:0 0 auto }

/* An acceptance is a whole sentence rather than one word, so it wraps - and a
   wrapped sentence next to a centered box leaves the box floating halfway down
   it. The box sits on the first line, where the sentence starts. */
.dsf-accept{ align-items:flex-start }
.dsf-accept > span{ flex:1 1 auto; min-width:0 }

.dsf-note{ display:block; margin-top:4px; font-size:.875em; opacity:.75 }

/* Something wrong, said next to the thing that is wrong with it. */
.dsf-fault{ display:block; margin-top:4px; font-size:.875em; color:var(--ds-w-bad,#b32d2e) }
.dsf-field.has-fault input,
.dsf-field.has-fault select,
.dsf-field.has-fault textarea{ border-color:var(--ds-w-bad,#b32d2e) }

/* These sit in the form's own stack rather than in the field columns, so they
   are full width by being where they are and have no span to declare. */
.dsf-trouble{ margin:0; color:var(--ds-w-bad,#b32d2e) }
.dsf-thanks{ margin:0 }
.dsf-must{ opacity:.6 }

.dsf-does{ margin:0 }

/* Where the page jumps to after a submission, so somebody lands on the answer
   rather than at the top of a long page wondering what happened.

   Out of the flow, not out of the document. It has no height, but it was still
   a flex child, so the column's gap was spent between it and the first field -
   the form began with a blank band as tall as Between fields, growing with the
   setting, with nothing in it. Absolute leaves a box at the top of the form for
   the jump to land on and takes it out of the layout entirely. */
.dsf-anchor{ height:0; margin:0; outline:none;
  position:absolute; top:0; left:0; width:0; pointer-events:none }

/* And the same at the other end. The foot carries the reply and the challenge,
   and a form whose send button sits in the field grid has neither - so it was
   an empty box earning a gap above it. :has rather than :empty, because the
   challenge arrives later and the foot has to come back when it does. */
.dsf-foot:not(:has(*)){ display:none }

/* The hidden inputs a form has to carry and nobody should ever see.
 *
 * display:none, not off-screen: unlike the honeypot below, nothing is meant to
 * find these. A hidden input still posts its value from inside a display:none
 * wrapper - only `disabled` stops that - so the form sends exactly what it did
 * before and draws nothing where they sit.
 *
 * They are inside the fields grid, so without this the wrapper is a grid item
 * and takes a whole row and the grid's gap: an empty band between the last
 * field and the button. */
.dsf-keep{ display:none }

/* The field nothing should ever fill in.
 *
 * Off-screen rather than display:none: some bots skip anything that is not
 * being drawn, and the whole point is that this one gets filled in. Hidden from
 * screen readers by aria-hidden on the wrapper, so nobody is ever asked to
 * complete it. */
.dsf-hope{
  position:absolute !important;
  left:-9999px !important;
  top:auto !important;
  width:1px !important;
  height:1px !important;
  overflow:hidden !important;
}

/* ------------------------------------------------------ a form in steps */
/* Which step, of how many. Buttons rather than text, so a step already
   answered can be gone back to by pressing its name. */
/* The fields sit in a twelve column grid, so anything put between the grid
   and them becomes a single cell of it - the step wrapper was one column
   wide with a whole step crushed inside it. Both the bar and each step
   span the full row, and a step carries the same grid inside itself so the
   fields lay out exactly as they did before there were steps. */
.dsf-steps, .dsf-step{ grid-column:1 / -1 }
.dsf-step{ display:grid; gap:14px 16px;
  grid-template-columns:repeat(12,minmax(0,1fr)) }
.dsf-steptitle, .dsf-stepnav{ grid-column:1 / -1 }

/* A section heading, over the group under it.
   The whole row whatever width the field was given, and more space above than
   below so it reads as belonging to what follows rather than to what came
   before. Nothing above the first one, which would push the form off the
   things laid out beside it. */
.dsf-section{ grid-column:1 / -1; margin:18px 0 2px }
.dsf-section:first-child{ margin-top:0 }

.dsf-steps{ display:flex; flex-wrap:wrap; gap:8px; list-style:none;
  margin:0 0 24px; padding:0 }
.dsf-steplink{ margin:0 }
.dsf-steplink button{ display:flex; align-items:center; gap:8px;
  background:none; border:0; padding:6px 2px; cursor:pointer; font:inherit;
  color:inherit; opacity:.5 }
.dsf-steplink.is-on button, .dsf-steplink.is-done button{ opacity:1 }
.dsf-steplink button:hover{ opacity:1 }

/* The number, in a ring.
 *
 * Never filled. The step being answered used to have a solid circle with
 * the digit set to the page background - a token this stylesheet cannot
 * count on, so it fell back to white on a white fill and the number simply
 * vanished on whichever step you were looking at. The current step is told
 * apart by weight and a heavier ring instead, which cannot depend on a
 * color that may not be there. */
.dsf-stepnum{ display:inline-flex; align-items:center; justify-content:center;
  width:1.75em; height:1.75em; border-radius:50%; font-size:.85em;
  border:1px solid currentColor; flex:0 0 auto }
.dsf-steplink.is-on .dsf-stepnum{ border-width:2px; font-weight:600 }
.dsf-steplink.is-on .dsf-stepname{ font-weight:600 }

.dsf-step[hidden]{ display:none }
.dsf-steptitle{ margin:0 0 16px }

/* Back on the left, Next on the right, whichever of the two is there. */
.dsf-stepnav{ display:flex; justify-content:space-between; gap:12px;
  margin-top:24px }
.dsf-stepnav .dsf-next{ margin-left:auto }

.dsf-does[hidden]{ display:none !important }

/* ------------------------------------------------------------ signature */
.dsf-sign{ display:block }

/* touch-action so a finger draws instead of scrolling the page - without it
   a signature on a phone is impossible, because the first stroke scrolls.
   Height in the markup as well; a canvas sized only here draws at 300x150
   and stretches, which smears the line. */
.dsf-signpad{ display:block; width:100%; height:auto; aspect-ratio:3 / 1;
  touch-action:none; cursor:crosshair; border:1px solid currentColor;
  border-radius:8px }

.dsf-signclear{ margin-top:8px; background:none; border:0; padding:0;
  font:inherit; color:inherit; opacity:.6; cursor:pointer;
  text-decoration:underline }
.dsf-signclear:hover{ opacity:1 }

/* A signature shown back on an admin screen or in an entry. */
.dsf-signshown{ max-width:320px; height:auto; border:1px solid currentColor;
  border-radius:8px }

/* The send button as a field.
 *
 * It sits in the grid with everything else, so its width is the field's width -
 * half or full - rather than a setting of its own. Full means the button fills
 * the field, which is what a form in a narrow column wants; on a half field it
 * is its own size, the way a button normally sits. */
/* The button is drawn at its own size unless it was asked to fill. The field
   it sits in does not decide that - a button in a full width field is not
   always meant to be a full width button. */
.dsf-field.dsf-submit{ display:flex; align-items:flex-end }
.dsf-send.is-wide{ width:100% }

/* An empty paragraph is not spacing.
 *
 * The captcha brings a <script> with it, and wpautop wraps a bare script in a
 * paragraph - so the foot carried an empty block with a paragraph's margins top
 * and bottom, which read as a gap above the send button that nobody had asked
 * for. It holds nothing and is drawn as nothing. */
/* A paragraph holding nothing but a script draws nothing, so it is nothing.
   :empty does not match it - the script is a child - so it is matched by what
   it contains. The margins are what made the gap; the box itself has no
   height. */
.dsf-foot > p:empty,
.dsf-fields > p:empty,
.dsf-foot > p:has(> script:only-child),
.dsf-fields > p:has(> script:only-child){ display:none }

/* The challenge across the column it sits in.
   Turnstile's flexible size fills whatever it is given and stops at 300px on
   its own otherwise, so the box around it is what decides the width. */
/* The fields are a twelve column grid and the challenge is dropped in
   without a span, so it took one column - seventy pixels - and the widget
   spilled out of it at its own minimum. */
.dsf-fields > .dss-guard,
.dsf-fields > .dst-guard,
/* And the line it says when a challenge fails. Same reason as the challenge
   above it: a grid item with no span takes one of the twelve columns, and a
   whole sentence in a 61px column is a 428px tall stack of one-word lines with
   the send button under it. It is hidden until something goes wrong, so this
   only shows when the form is already having a bad day. */
.dsf-fields > .dss-guard-said{ grid-column:1 / -1 }
/* And one that draws nothing takes no room.
   The fields are a grid with a gap and every child gets one whether it draws
   anything or not, so an invisible challenge - an empty div - and the block
   holding its scripts took a gap each: 28px of space under a challenge nobody
   can see. The iframe is the test: a challenge that is actually drawn holds
   one, and an invisible one does not. :empty was tried first and is wrong -
   an invisible challenge puts a hidden input for its token inside the div, so
   it stops being empty the moment Cloudflare answers and the gap came back. */
.dsf-fields > .dss-guard:not(:has(iframe)),
.dsf-fields > .dst-guard:not(:has(iframe)),
.dsf-fields > .dss-guard-js{ display:none }
.dsf-form .dss-guard,
.dsf-form .dst-guard{ width:100%; max-width:100% }
.dsf-form .dss-guard > *,
.dsf-form .dst-guard > *{ width:100%; max-width:100% }
.dsf-form .dss-guard iframe,
.dsf-form .dst-guard iframe{ width:100%; max-width:100%; border:0 }
