/* ============================================================================
   America Éire — Forms
   The form-control layer of the design system. Extends tokens.css into inputs,
   selects, textareas, file inputs, buttons, labels, help text, and error
   states. Derived from building the story submission form (the first real form
   on the site); documented in the `design` book once stable.

   Principles, all inherited from the established system:
     - Forms are UI, so Tenon throughout — Stoker appears nowhere here.
     - Gold (--color-rule) is the resting hairline; Forest green (--color-heading)
       is the focus/active color. There is NO light green in the palette, so
       focus is signalled by the forest border + a soft gold ring, never a tint.
     - Rust (--color-accent) is reserved for the required marker and errors —
       sparing, as the system demands.
     - Spacing uses the --space-* scale so fields stay in rhythm with the type.
     - Inputs sit on cream-deep (--color-bg-layer) so they read as insets on the
       cream page without needing a box-shadow.
   ========================================================================== */

/* --- The form shell ------------------------------------------------------- */
.form {
  max-width: 42rem;          /* narrower than --measure: a form reads best tight */
}

/* A field: label + control + optional help/error, stacked. The vertical
   rhythm between fields is the form's main spacing decision. */
.field {
  margin-bottom: var(--space-m);
}
.field:last-of-type {
  margin-bottom: 0;
}

/* Group two fields side by side on wider screens (county + state, name + family
   name). Collapses to stacked on narrow viewports. */
/* Align the CONTROLS across the row. Both fields in a row share the same
   pre-input stack (label + one line of help--above), so aligning the cells
   from the TOP keeps the inputs on the same line — and, crucially, a one-sided
   validation error (which adds height BELOW an input) no longer shifts its
   error-free neighbour. Earlier this bottom-pinned the controls (margin-top:
   auto) to absorb uneven help-text length; that handled a case the real form
   never has (both helps are one line) while causing the visible bug it didn't:
   an error stretched the grid row and the sibling's auto-margin pushed its
   input down to meet the taller cell. Top alignment is the robust choice here.
   If a future row ever needs uneven multi-line help to still align its inputs,
   give .field-row .help--above a min-height rather than reintroducing the
   bottom-sink. */
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: start;
  gap: var(--space-s-m);
  margin-bottom: var(--space-m);
}
/* Align the CONTROLS across the row even when help-text length differs
   (e.g. the name row: long help left, short help right). Grid already
   stretches both cells to equal height; flex + margin-top:auto sinks each
   control to the cell's bottom, so the spare space lands between the shorter
   help and its control — aligned inputs, breathing room above. Deliberately
   not subgrid: the two rows have different internal stacks (help--above vs
   none, conditional error spans), and this needs no row-count contract.
   Known soft spot: a one-sided validation error re-staggers the controls by
   the error's height — acceptable, error states are transient and the
   message must stay adjacent to its field. On mobile (stacked, auto-height
   cells) margin-top:auto resolves to 0 and this is inert. */
.field-row .field {
  display: flex;
  flex-direction: column;
  margin-bottom: 0;   /* row rhythm lives on .field-row — see above. Same
                         specificity as .field:last-of-type (0,2,0); this
                         wins by source order, deliberately, for BOTH cells. */
}
@media (max-width: 34rem) {
  /* Stacked: fields carry their own rhythm again (as everywhere else in the
     form), so the row's margin must come off or the row ends double-spaced. */
  .field-row { grid-template-columns: 1fr; gap: 0; margin-bottom: 0; }
  .field-row .field { margin-bottom: var(--space-m); }
}

/* --- Labels --------------------------------------------------------------- */
.field > label {
  display: block;
  font-family: var(--font-sans);
  font-weight: 500;
  color: var(--color-heading);          /* forest — labels read as quiet headings */
  margin-bottom: var(--space-2xs);
  line-height: 1.3;
}

/* Required marker — a rust asterisk. The one place rust enters a resting form. */
.field > label .req {
  color: var(--color-accent);
  margin-left: 0.15em;
  font-weight: 500;
}

/* Help text — stone, small, sits under the label or control. The forgiving
   helper copy (year-of-departure, word-count guidance) lives here. */
.field .help {
  display: block;
  color: var(--color-subdued);
  font-size: var(--step--1);
  line-height: 1.5;
  margin-top: var(--space-3xs);
}
/* Help shown ABOVE the control (between label and input) wants bottom margin. */
.field .help--above {
  margin-top: 0;
  margin-bottom: var(--space-2xs);
}
/* Shared helper that captions a whole .field-row (sits as a sibling AFTER the
   row, full-width under both columns). The row carries margin-bottom:space-m,
   so to make THIS caption's gap above it match a normal single-field .help
   (which sits space-3xs below its control), cancel the row's bottom margin and
   add back that small gap: space-3xs − space-m. Earlier this used a flat
   negative pull (−space-2xs), which read tighter than the single-field help and
   looked inconsistent (caught June 17). Not inside .field, so it needs its own
   display/type rules. */
.help--row {
  display: block;
  color: var(--color-subdued);
  font-size: var(--step--1);
  line-height: 1.5;
  margin-top: calc(var(--space-3xs) - var(--space-m));  /* gap matches .field .help */
  margin-bottom: var(--space-m);            /* inter-field rhythm before the next field */
}

/* --- Form group heading + intro -------------------------------------------
   A sub-section title WITHIN the form (e.g. "Social profiles"). Uses the label
   register — forest, Tenon, 500 — so it belongs to the form's vocabulary, but
   one step larger than a field label so it reads as a group title rather than
   a single field's label. NOT a kicker (too quiet/gold, reads as fine print)
   and NOT an h2 (Stoker display, far too loud beside the plain field labels).
   Generous top margin sets the group apart from the field above it. */
.form-group-heading {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--step-1);
  color: var(--color-heading);          /* forest, like labels */
  line-height: 1.2;
  margin-top: var(--space-xl);          /* separate the group from the field above */
  margin-bottom: var(--space-3xs);
}
.form-group-heading__opt {
  font-weight: 400;
  color: var(--color-subdued);          /* "(optional)" recedes — stone, regular */
}
/* Intro/help line under a group heading. The help register (stone, small), but
   with real bottom margin so the first field-row below it clears the text —
   the row's own top edge sits tight otherwise (caught in Chrome). */
.form-group-intro {
  color: var(--color-subdued);
  font-size: var(--step--1);
  line-height: 1.5;
  max-width: 42rem;
  margin-bottom: var(--space-s);        /* breathing room before the first row */
}

/* --- Text controls -------------------------------------------------------- */
input[type="text"],
input[type="email"],
input[type="url"],
select,
textarea {
  width: 100%;
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.5;
  color: var(--color-text);
  background: var(--color-bg-layer);     /* cream-deep inset on the cream page */
  border: 1px solid var(--color-rule);   /* gold hairline at rest */
  border-radius: 2px;                    /* barely there — the system is square-ish */
  padding: var(--space-2xs) var(--space-xs);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  -webkit-appearance: none;
  appearance: none;
}

textarea {
  line-height: 1.5;                      /* tighter than the editorial 1.8 — a typing
                                            context wants compactness, not air. The
                                            story page renders prose at the full 1.8. */
  resize: vertical;
  min-height: 14rem;
}

/* Placeholder — stone, never mistaken for a filled value. */
::placeholder {
  color: var(--color-subdued);
  opacity: 0.8;
}

/* Focus — forest border + soft gold ring. No outline (we draw our own). */
input[type="text"]:focus,
input[type="email"]:focus,
input[type="url"]:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--color-heading);    /* forest */
  box-shadow: 0 0 0 3px rgba(169, 133, 47, 0.22);  /* gold, low alpha */
}

/* --- Select --------------------------------------------------------------- */
/* Native appearance stripped; a gold chevron drawn as a background SVG so the
   control matches the hairline system rather than the OS. */
select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23a9852f' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-xs) center;
  padding-right: var(--space-l);         /* room for the chevron */
  cursor: pointer;
}
/* A select with no value yet (the placeholder option) reads as subdued. */
select:invalid,
select.is-placeholder {
  color: var(--color-subdued);
}

/* --- File input ----------------------------------------------------------- */
/* The native control is replaced by a styled label that triggers a visually
   hidden <input type=file>. The chosen filename is written into .file-name by
   the page script. */
.file {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  flex-wrap: wrap;
}
.file input[type="file"] {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}
.file-button {
  display: inline-block;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-heading);
  background: var(--color-bg-layer);
  border: 1px solid var(--color-rule);
  border-radius: 2px;
  padding: var(--space-2xs) var(--space-s);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.file input[type="file"]:focus + .file-button {
  border-color: var(--color-heading);
  box-shadow: 0 0 0 3px rgba(169, 133, 47, 0.22);
}
.file-button:hover {
  border-color: var(--color-heading);
}
.file-name {
  font-size: var(--step--1);
  color: var(--color-subdued);
  font-style: italic;
}

/* --- Checkbox ------------------------------------------------------------- */
/* Marketing opt-in. The real <input> is styled directly with appearance:none
   (rather than hidden behind a sibling span) so the box can use forest/gold
   instead of the OS accent while staying the actual focusable control. The
   checkmark is a rotated-border pseudo-element on :checked. */
label.check {
  /* label.check, NOT .check: inside a .field, the generic `.field > label`
     (0,1,1, display:block) outranked bare `.check` (0,1,0) and silently
     flattened this flex layout into inline flow — long labels wrapped under
     the BOX instead of hanging under the text (caught June 11 when the
     opt-in copy grew to two lines). label.check ties at (0,1,1) and wins by
     source order. flex-start (not center): centering was tuned for one-line
     labels; on two lines it floats the box between them — the box should
     ride the first line. */
  display: flex;
  align-items: flex-start;
  gap: var(--space-xs);
  cursor: pointer;
  line-height: 1.3;
  max-width: 42rem;
}
.check input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  width: 1.15rem; height: 1.15rem;
  margin: 0;
  transform: translateY(0.15em);         /* optical nudge for flex-start: drop the
                                            box from the line-box top onto the first
                                            line's glyph band. Eyeball-tune ±1px if
                                            it sits high/low against Tenon. */
  border: 1px solid var(--color-rule);   /* gold hairline at rest */
  border-radius: 2px;
  background: var(--color-bg-layer);
  position: relative;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.check input[type="checkbox"]:checked {
  border-color: var(--color-heading);
  background: var(--color-heading);      /* forest fill when checked */
}
.check input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 0.36em; top: 0.14em;
  width: 0.3em; height: 0.58em;
  border: solid var(--color-bg);         /* cream check on forest */
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.check input[type="checkbox"]:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(169, 133, 47, 0.22);
}
/* The opt-in label is content the person consents to, not a field label and not
   fine print. So: body size and pine (readable, a real choice) but REGULAR
   weight, not the 500/forest of labels — that weight+colour gap is what keeps it
   from reading as a label. Tighter line-height keeps the box optically centered.
   Calibrated live in Tenon. */
.check .check-text {
  font-size: var(--step-0);
  color: var(--color-text);
  font-weight: 400;
  line-height: 1.3;
}

/* --- Submit button -------------------------------------------------------- */
/* Forest fill, cream text — the one solid, confident element in the form.
   (Distinct from the .file-button, which is a quiet bordered secondary.) */
.btn {
  display: inline-block;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--step-0);
  letter-spacing: 0.04em;
  color: var(--color-bg);
  background: var(--color-heading);      /* forest */
  border: 1px solid var(--color-heading);
  border-radius: 2px;
  padding: var(--space-xs) var(--space-l);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.btn:hover {
  background: var(--pine);               /* deepens on hover, like the link system */
  border-color: var(--pine);
}
.btn:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(169, 133, 47, 0.30);
}

/* --- Validation / error states -------------------------------------------- */
/* A field in error: rust border on the control, rust message below. Applied by
   the server re-rendering the form with .has-error on the .field. */
.field.has-error input[type="text"],
.field.has-error input[type="email"],
.field.has-error input[type="url"],
.field.has-error select,
.field.has-error textarea {
  border-color: var(--color-accent);     /* rust */
}
.field.has-error input:focus,
.field.has-error select:focus,
.field.has-error textarea:focus {
  box-shadow: 0 0 0 3px rgba(196, 74, 42, 0.20);  /* rust ring */
}
.field .error {
  display: block;
  color: var(--color-accent);
  font-size: var(--step--1);
  font-weight: 500;
  margin-top: var(--space-3xs);
}

/* --- Form-level notices --------------------------------------------------- */
/* A summary banner at the top of the form on submit failure, and the success
   confirmation shown after a successful POST→redirect. */
.notice {
  padding: var(--space-s) var(--space-m);
  border-radius: 2px;
  margin-bottom: var(--space-l);
  line-height: 1.6;
}
.notice--error {
  background: rgba(196, 74, 42, 0.08);
  border: 1px solid var(--color-accent);
  color: var(--rust-deep);
}
.notice--success {
  background: rgba(31, 58, 46, 0.06);
  border: 1px solid var(--color-rule);
  color: var(--color-heading);
}
.notice strong { font-weight: 500; }
