/* Text field: the bordered input box, adornments, clear, password reveal,
   number steppers and the textarea. Label, hint and error come from field.css.
   Contract: docs/ui/CONVENTIONS.md. */
@layer components {
  .text-field {
    --tf-h: var(--control-md);
    --tf-px: var(--space-3);
    --tf-font: var(--text-md);
    --tf-line: var(--line-md);
    --tf-bg: var(--color-surface);
    --tf-bg-hover: var(--tf-bg);
    --tf-border: var(--color-border-control);
    --tf-focus: var(--color-accent);
    --tf-halo: var(--focus-halo);
    --icon-size: var(--icon-sm);
    /* In-box actions (clear, reveal, steppers, toggles) and chips: one inset rule. The gap between
       them, and between them and the box edge (top, bottom and end), is --tf-action-gap; their size
       fills what is left of the box height, so all four distances are equal. */
    --tf-action-gap: var(--space-1);
    --tf-action: calc(var(--tf-h) - 2px - 2 * var(--tf-action-gap));

    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    min-width: 0;
    height: var(--tf-h);
    padding-inline: var(--tf-px);
    border: 1px solid var(--tf-border);
    border-radius: var(--radius-control);
    background: var(--tf-bg);
    color: var(--color-text);
    font-size: var(--tf-font);
    line-height: var(--tf-line);
    cursor: text;
    transition:
      border-color var(--t-fast) var(--ease-std),
      background-color var(--t-fast) var(--ease-std),
      box-shadow var(--t-fast) var(--ease-std);

    &[data-size="sm"] { --tf-h: var(--control-sm); --tf-px: var(--control-px-sm); --tf-font: var(--text-sm); --tf-line: var(--line-sm); }
    &[data-size="lg"] { --tf-h: var(--control-lg); --tf-px: var(--control-px-md); --tf-font: var(--text-lg); --tf-line: var(--line-lg); --icon-size: var(--icon-md); }


    /* A trailing action sits --tf-action-gap from the end border instead of the text padding. */
    /* "Last" ignores hidden form inputs after it (the date picker adds one). :has() cannot be nested,
       so this uses :nth-last-child(1 of ...). */
    &:has(> :is(.text-field-action, .text-field-steppers):nth-last-child(1 of :not(input[type="hidden"], template))) { padding-inline-end: var(--tf-action-gap); }

    &:hover { background: var(--tf-bg-hover); border-color: var(--color-text-muted); }

    /* Focus: a 2px accent edge (border plus inset ring) and the soft halo. The input's own outline
       is dropped because the whole box carries the ring. */
    &:focus-within {
      border-color: var(--tf-focus);
      box-shadow: inset 0 0 0 1px var(--tf-focus), var(--tf-halo);
    }

    /* Only aria-invalid, which form.js sets on submit. Never :invalid/:user-invalid: the browser
       updates those as the user types. */
    &:has(.text-field-input[aria-invalid="true"]) {
      --tf-border: var(--color-danger);
      --tf-focus: var(--color-danger);
      --tf-halo: 0 0 0 3px var(--color-danger-soft-hover);
      &:hover { border-color: var(--color-danger); }
    }

    &:has(.text-field-input[readonly]) {
      --tf-bg: var(--color-surface-muted);
      --tf-bg-hover: var(--tf-bg);
      --tf-border: var(--color-border-strong);
      &:hover { border-color: var(--tf-border); }
    }

    &:has(.text-field-input:disabled) {
      --tf-bg: var(--color-surface-muted);
      --tf-bg-hover: var(--tf-bg);
      --tf-border: var(--color-border);
      color: var(--color-text-disabled);
      cursor: not-allowed;
      box-shadow: none;
      &:hover { border-color: var(--tf-border); }
      .text-field-icon, .text-field-affix { color: var(--color-text-disabled); }
    }

    /* Multi-line: textarea, top-aligned adornments. */
    &[data-multiline] {
      align-items: flex-start;
      height: auto;
      min-height: var(--tf-h);
      padding-block: var(--tf-px);
      > .text-field-icon, > .text-field-affix { height: var(--tf-line); }
    }

    /* Wrapping content (chips before the input, as in the multiple combobox). */
    /* Chips and actions keep the same --tf-action-gap from the border and from each other; the
       text still starts --tf-px from the border when there are no chips. */
    &[data-wrap] {
      flex-wrap: wrap;
      height: auto;
      min-height: var(--tf-h);
      gap: var(--tf-action-gap);
      padding: var(--tf-action-gap);
      > .text-field-input { flex: 1 1 6em; height: var(--tf-action); padding-inline-start: calc(var(--tf-px) - var(--tf-action-gap)); }
    }
  }

  .text-field-input {
    flex: 1;
    min-width: 0;
    height: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: inherit;
    font-size: var(--tf-font);
    line-height: var(--tf-line);
    &:focus-visible { outline: none; }
    &:disabled { cursor: not-allowed; color: var(--color-text-disabled); -webkit-text-fill-color: var(--color-text-disabled); }
    &::placeholder { color: var(--color-text-muted); }
    &::-webkit-search-cancel-button { appearance: none; }
  }
  textarea.text-field-input {
    height: auto;
    resize: vertical;
    &[data-autogrow] { resize: none; field-sizing: content; min-height: calc(var(--tf-line) * 2); max-height: calc(var(--tf-line) * 12); }
  }
  input.text-field-input[type="number"] {
    appearance: textfield;
    -moz-appearance: textfield;
    font-variant-numeric: tabular-nums;
    &::-webkit-inner-spin-button, &::-webkit-outer-spin-button { appearance: none; margin: 0; }
  }

  /* iOS zooms into inputs under 16px; touch devices get 16px text at every size. */
  @media (pointer: coarse) {
    .text-field-input { font-size: var(--text-lg); }
  }

  .text-field-icon {
    display: inline-flex;
    align-items: center;
    flex: none;
    color: var(--color-text-muted);
  }
  .text-field-affix {
    display: inline-flex;
    align-items: center;
    flex: none;
    color: var(--color-text-muted);
    white-space: nowrap;
  }

  /* Square buttons inside the box: clear, reveal, steppers, combobox and date-picker toggles.
     Sized and spaced by --tf-action / --tf-action-gap (see .text-field). */
  .text-field-action {
    --icon-size: var(--icon-sm);
    display: inline-grid;
    place-items: center;
    flex: none;
    width: var(--tf-action);
    height: var(--tf-action);
    border-radius: var(--radius-xs);
    color: var(--color-text-muted);
    cursor: pointer;
    transition: background-color var(--t-fast) var(--ease-std), color var(--t-fast) var(--ease-std);
    &:hover { background: var(--color-overlay-hover); color: var(--color-text); }
    &:focus-visible { outline: none; background: var(--color-overlay-hover); color: var(--color-text); } /* no ring: the hover fill marks keyboard focus */
    &:disabled { color: var(--color-text-disabled); background: none; }
  }
  /* Adjacent actions: --tf-action-gap apart (the box's own gap is larger, for text and affixes). */
  .text-field > :is(.text-field-action, .text-field-steppers) + :is(.text-field-action, .text-field-steppers) {
    margin-inline-start: calc(var(--tf-action-gap) - var(--space-2));
  }
  .text-field:has(.text-field-input:placeholder-shown) [data-text-field-clear] { display: none; }
  .text-field-when-shown { display: none; }
  [aria-pressed="true"] > .text-field-when-shown { display: inline-block; }
  [aria-pressed="true"] > .text-field-when-hidden { display: none; }
  .text-field-steppers { display: inline-flex; flex: none; gap: var(--tf-action-gap); }
}
