/* ==========================================================================
   .tp-input — P1.F2.T3
   ©2026 Vexstorm Studios – All Rights Reserved

   The text-entry family: input, textarea, and the field furniture around them
   (label, hint, error, character counter, prefix/suffix).

   Variants   --textarea  --small  --mono
   Elements   __field  __label  __hint  __error  __required  __affix  __control
   States     :hover  :focus-visible  :disabled  :read-only  [aria-invalid]

   Form + View Pattern: an error is programmatically associated with its field
   through aria-describedby, and the error is announced by an icon and the word
   "Error" as well as by the red ring — colour is never the only signal that a
   field is wrong (ACC-004, ACC-003).
   ========================================================================== */

/* The field group: label, control, hint, error. */
.tp-input {
  display: flex;
  flex-direction: column;
  gap: var(--tp-space-2);
  min-width: 0;
}

.tp-input__label {
  color: var(--tp-color-text-primary);
  font-size: var(--tp-text-sm);
  font-weight: var(--tp-weight-medium);
  line-height: var(--tp-leading-tight);
}

/* "(required)" is rendered as text beside the label, not as a bare asterisk:
   an asterisk alone is a convention, not a label (ACC-003). */
.tp-input__required {
  color: var(--tp-color-text-muted);
  font-weight: var(--tp-weight-regular);
}

/* The control itself. */
.tp-input__field {
  width: 100%;
  min-height: var(--tp-space-8);
  padding: var(--tp-space-2) var(--tp-space-3);
  border: var(--tp-border-width-hairline) solid var(--tp-color-border-default);
  border-radius: var(--tp-radius-md);
  background-color: var(--tp-color-surface-raised);
  color: var(--tp-color-text-primary);
  font-family: var(--tp-font-sans);
  font-size: var(--tp-text-base);
  line-height: var(--tp-leading-normal);
  transition:
    border-color var(--tp-motion-duration-fast) var(--tp-motion-ease-standard),
    background-color var(--tp-motion-duration-fast) var(--tp-motion-ease-standard);
}

.tp-input__field::placeholder {
  color: var(--tp-color-text-muted);
  /* A placeholder is never a label. It carries format examples only, so it may
     be de-emphasised but must still be legible. */
  opacity: 1;
}

.tp-input__field:hover {
  border-color: var(--tp-color-border-strong);
}

.tp-input__field:disabled {
  background-color: var(--tp-color-surface-sunken);
  color: var(--tp-color-text-muted);
  border-color: var(--tp-color-border-subtle);
  opacity: var(--tp-opacity-disabled);
  cursor: not-allowed;
}

/* Read-only is not disabled: the value is still selectable and copyable,
   which matters for identifiers and generated codes. */
.tp-input__field:read-only {
  background-color: var(--tp-color-surface-sunken);
  border-color: var(--tp-color-border-subtle);
}

/* Invalid. The ring is one signal; .tp-input__error below is the other. */
.tp-input__field[aria-invalid="true"] {
  border-color: var(--tp-color-state-danger);
  border-width: var(--tp-border-width-thick);
  background-color: var(--tp-color-state-danger-subtle);
}

.tp-input__field:focus-visible {
  border-color: var(--tp-color-border-focus);
}

/* --------------------------------------------------------------------------
   Variants
   -------------------------------------------------------------------------- */

.tp-input__field--textarea {
  min-height: var(--tp-space-11);
  resize: vertical;
}

.tp-input__field--small {
  min-height: var(--tp-space-7);
  padding: var(--tp-space-1) var(--tp-space-2);
  font-size: var(--tp-text-sm);
}

/* Identifiers, codes, and anything the user will compare character by
   character. */
.tp-input__field--mono {
  font-family: var(--tp-font-mono);
  font-size: var(--tp-text-sm);
  letter-spacing: 0.02em;
}

/* --------------------------------------------------------------------------
   Supporting text
   -------------------------------------------------------------------------- */

/* Referenced from the field's aria-describedby. */
.tp-input__hint {
  color: var(--tp-color-text-muted);
  font-size: var(--tp-text-sm);
  line-height: var(--tp-leading-normal);
}

/* Also referenced from aria-describedby, and rendered in a role="alert"
   container by the form template so a late-arriving server error is
   announced. The icon and the leading word carry the meaning alongside the
   colour. */
.tp-input__error {
  display: flex;
  align-items: flex-start;
  gap: var(--tp-space-2);
  color: var(--tp-color-state-danger-text);
  font-size: var(--tp-text-sm);
  font-weight: var(--tp-weight-medium);
  line-height: var(--tp-leading-normal);
}

.tp-input__error-icon {
  width: var(--tp-space-icon);
  height: var(--tp-space-icon);
  flex: none;
  margin-top: var(--tp-space-1);
  color: var(--tp-color-state-danger);
}

/* --------------------------------------------------------------------------
   Affixes — a unit, a currency, a search icon, or a "clear" button attached to
   the control without leaving the field's hit area.
   -------------------------------------------------------------------------- */

.tp-input__control {
  display: flex;
  align-items: stretch;
  gap: var(--tp-space-2);
  min-width: 0;
}

.tp-input__affix {
  display: inline-flex;
  align-items: center;
  gap: var(--tp-space-1);
  padding-inline: var(--tp-space-3);
  border: var(--tp-border-width-hairline) solid var(--tp-color-border-default);
  border-radius: var(--tp-radius-md);
  background-color: var(--tp-color-surface-sunken);
  color: var(--tp-color-text-secondary);
  font-size: var(--tp-text-sm);
  white-space: nowrap;
}
