/* =============================================================================
   Forms — fields, selects, textareas, checkboxes/radios, validation states and
   the submit spinner. docs/components/form-controls.md.

   The app's only form is pages/contact.html (Formspree). Its privacy checkbox
   is a bare `required` <input type="checkbox">: there is no `.checkbox > .box`
   wrapper as form-controls.md's markup assumes, so the native control is
   restyled in place with `appearance: none` rather than hidden behind a span.
   That keeps it in the DOM, focusable and — critically — visible.
   ============================================================================= */

/* ---------------------------------------------------------------------------
   Layout — label ↔ control gap is 8px, field ↔ field is 20px
   --------------------------------------------------------------------------- */
.form {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.form__group {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.form__row {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-5);
}

@media (max-width: 900px) {
  .form__row {
    grid-template-columns: 1fr;
  }
}

/* ---------------------------------------------------------------------------
   Label — typographyLabel: 14px / 600 / letter-spacing 5%
   --------------------------------------------------------------------------- */
.form__label {
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 140%;
  letter-spacing: 0.05em;
  color: var(--color-primary);
}

.form__label--required::after {
  content: ' *';
  color: var(--color-error);
}

/* ---------------------------------------------------------------------------
   Input / select / textarea — 48px tall, 16px side padding, 8px radius,
   1px border. The focus ring is a 2px cyan edge drawn as border + inset
   shadow so the box never shifts by a pixel.
   --------------------------------------------------------------------------- */
.form__input,
.form__select,
.form__textarea {
  width: 100%;
  height: 48px;
  padding: 0 var(--space-4);
  font-size: 0.9375rem;
  line-height: 160%;
  color: var(--color-primary);
  background-color: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius);
  transition: background-color var(--duration-fast) var(--ease-standard),
              border-color var(--duration-fast) var(--ease-standard),
              outline-color var(--duration-fast) var(--ease-standard);
}

/* iOS Safari zooms the viewport when a focused control is below 16px.
   The design system's control size is 15px, so it is raised on mobile only. */
@media (max-width: 600px) {
  .form__input,
  .form__select,
  .form__textarea {
    font-size: 1rem;
  }
}

.form__input::placeholder,
.form__textarea::placeholder {
  color: var(--color-placeholder);
}

.form__input:hover,
.form__select:hover,
.form__textarea:hover {
  background-color: var(--color-control-hover-bg);
}

/* The ring is drawn as an inset outline rather than a thicker border, so the
   box never shifts by a pixel and the single 2px edge replaces — rather than
   doubles — the global :focus-visible ring from globals.css. */
.form__input:focus,
.form__select:focus,
.form__textarea:focus {
  background-color: var(--color-white);
  border-color: var(--focus-ring, var(--color-primary));
  outline: 2px solid var(--focus-ring, var(--color-primary));
  outline-offset: -2px;
}

.form__input:disabled,
.form__select:disabled,
.form__textarea:disabled {
  color: var(--color-disabled-text);
  background-color: var(--color-disabled-bg);
  border-color: var(--color-disabled-border);
  cursor: not-allowed;
}

.form__textarea {
  height: auto;
  min-height: 150px;
  padding: var(--space-4);
  resize: vertical;
}

/* Chevron drawn from two gradients rather than an SVG data URI: a data URI
   cannot read a custom property, so its arrow colour could only be hardcoded. */
.form__select {
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  padding-right: var(--space-10);
  background-image:
    linear-gradient(45deg, transparent 50%, var(--color-text-gray) 50%),
    linear-gradient(135deg, var(--color-text-gray) 50%, transparent 50%);
  background-position: right var(--space-5) center, right var(--space-4) center;
  background-size: var(--space-1) var(--space-1);
  background-repeat: no-repeat;
}

/* ---------------------------------------------------------------------------
   Validation — js/main.js toggles .input--valid / .input--error from
   checkValidity() on blur. Both must outrank the focus ring above.
   --------------------------------------------------------------------------- */
.form__input.input--error,
.form__select.input--error,
.form__textarea.input--error {
  border-color: var(--color-error);
}

.form__input.input--error:focus,
.form__select.input--error:focus,
.form__textarea.input--error:focus {
  border-color: var(--color-error);
  outline-color: var(--color-error);
}

.form__input.input--valid,
.form__select.input--valid,
.form__textarea.input--valid {
  border-color: var(--color-success);
}

.form__input.input--valid:focus,
.form__select.input--valid:focus,
.form__textarea.input--valid:focus {
  border-color: var(--color-success);
  outline-color: var(--color-success);
}

/* ---------------------------------------------------------------------------
   Checkbox and radio — 20px box, 1.5px border, checked fills cyan-dark with a
   white mark. The mark is a clip-path, so no colour is smuggled through an
   encoded SVG.
   --------------------------------------------------------------------------- */
.form input[type='checkbox'],
.form input[type='radio'] {
  appearance: none;
  -webkit-appearance: none;
  display: inline-grid;
  place-content: center;
  flex: none;
  width: 20px;
  height: 20px;
  background-color: var(--color-white);
  border: 1.5px solid var(--color-border);
  border-radius: var(--border-radius-sm);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard),
              border-color var(--duration-fast) var(--ease-standard);
}

.form input[type='radio'] {
  border-radius: 50%;
}

.form input[type='checkbox']::before,
.form input[type='radio']::before {
  content: '';
  background-color: var(--color-white);
  transform: scale(0);
  transition: transform var(--duration-fast) var(--ease-standard);
}

.form input[type='checkbox']::before {
  width: 14px;
  height: 14px;
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
}

.form input[type='radio']::before {
  width: var(--space-2);
  height: var(--space-2);
  border-radius: 50%;
}

.form input[type='checkbox']:hover,
.form input[type='radio']:hover {
  background-color: var(--color-control-hover-bg);
  border-color: var(--color-accent-cyan-dark);
}

.form input[type='checkbox']:checked,
.form input[type='radio']:checked {
  background-color: var(--color-accent-cyan-dark);
  border-color: var(--color-accent-cyan-dark);
}

.form input[type='checkbox']:checked::before,
.form input[type='radio']:checked::before {
  transform: scale(1);
}

/* `:user-invalid` marks a required control only once the user has tried to
   submit or has left it — never on first paint. */
.form input[type='checkbox']:user-invalid,
.form input[type='radio']:user-invalid,
.form input[type='checkbox'].input--error,
.form input[type='radio'].input--error {
  border-color: var(--color-error);
}

.form input[type='checkbox']:disabled,
.form input[type='radio']:disabled {
  background-color: var(--color-disabled-control-bg);
  border-color: var(--color-border);
  cursor: not-allowed;
}

.form input[type='checkbox']:disabled:checked::before,
.form input[type='radio']:disabled:checked::before {
  background-color: var(--color-mid-gray);
}

/* ---------------------------------------------------------------------------
   Submit spinner — motion.md: 1.4s linear infinite, the one place `linear`
   is allowed.
   --------------------------------------------------------------------------- */
.spinner {
  animation: spin 1.4s linear infinite;
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
