/* ============================================================================
   Input / Default + Input / Default / Base — COMPONENTS.md §2.1–2.3

   The archetypes this flow needs, out of the 18 on `INPUT BASE`:
     · `Input`     — single-line text
     · `Select`    — the Medical group / Visit type pickers
     · `Text Area` — "Why do you need consultation?"

   §2.1 is a CLAUDE.md reference implementation and is followed exactly: the
   container fill is `surface/raised` in every state but Disabled, and the whole
   state machine rides on the border, 1px stepping to 2px on Focus.

   Findings implemented rather than reproduced:
     · §2 F1 — the label is `RAW #8c8c8c` in five sets where
       `content/secondary` resolves to the same value. `Input / Label` (§2.3)
       already binds it correctly; that is what this consumes.
     · §2 F2 — the error caption is `RAW #ea0b16`, which §10.1 identifies as
       `red/500` from the Toast page's local token system. `content/danger`.
     · §2 F3 — text styles are unbound almost everywhere on the page. Bound
       here: values `Body/MD Regular`, label and caption `Body/SM Regular`.
     · §2 F4 — disabled fields keep `content/primary` value text. Uses
       `content/disabled`, which is what that token is described for.
     · §2 F5 — on `Error=On`, Focus reuses `border/danger/default`, so "a
       keyboard user cannot see focus on an invalid field". Here an invalid
       field keeps the danger border AND takes the focus ring from base.css,
       so error identity and focus identity coexist.

   DESIGN.md §9.2 / root CLAUDE.md: `border/default` alone must not be the only
   thing delimiting a control. It is not — the field sits on `surface/raised`
   against a `surface/overlay` modal band, and required/invalid state is carried
   by text as well as colour.

   TODO(tokens): every bare px length in this file is a SIZE.
   ========================================================================== */

.field {
  display: flex;
  flex-direction: column;
  /* §2.2 geometry: 40 bare / 62 label / 84 label + caption, i.e. an 8px gap
     between label, field and caption. That is `space/2xs` + line boxes. */
  gap: var(--space-2xs);
}

/* --- Input / Label — §2.3 ------------------------------------------------ */
.field__label {
  color: var(--color-content-secondary);
  font-family: var(--font-family-text);
  font-size: var(--font-body-sm-size);
  line-height: var(--font-body-sm-line-height);
  font-weight: var(--font-weight-regular);
}

/* §2.3: asterisk is `content/danger`. Required is never signalled by the
   asterisk alone — the control also carries `aria-required`. */
.field__required {
  color: var(--color-content-danger);
}

.field__optional {
  color: var(--color-content-secondary);
}

/* --- Input / Default / Base — the bordered container --------------------- */
.field__control {
  display: flex;
  align-items: center;
  /* §2.1: root padding and gap are RAW 0 — "spacing lives entirely on the
     slots". The slots below carry `space/xs`. */
  padding: var(--space-none);
  background: var(--color-surface-raised);
  border: var(--border-width-thin) solid var(--color-border-default);
  border-radius: var(--shape-radius-input);
  transition: border-color 100ms ease; /* TODO(tokens): motion not built */
}

.field__control:hover {
  border-color: var(--color-border-brand-hover);
}

/* §2.1: Focus is a real state — `border/focus`, and the width steps 1 → 2,
   which matches `shape/focus/width`. */
.field__control:focus-within {
  border-color: var(--color-border-focus);
  border-width: var(--shape-focus-width);
}

/* --- The TXT slot ------------------------------------------------------- */
.field__input,
.field__select,
.field__textarea {
  flex: 1 1 auto;
  min-inline-size: 0;
  padding: var(--space-xs);
  border: 0;
  background: none;
  color: var(--color-content-primary);
  font-family: var(--font-family-text);
  font-size: var(--font-body-md-size);
  line-height: var(--font-body-md-line-height);
  font-weight: var(--font-weight-regular);
  letter-spacing: var(--font-letter-spacing-default);
}

.field__input,
.field__select {
  block-size: 38px; /* 40 less the 1px borders — §2.1 geometry */
}

/* The base's own focus ring is suppressed: the container already shows focus
   through `border/focus`, and base.css puts the ring on the outer control. */
.field__input:focus-visible,
.field__select:focus-visible,
.field__textarea:focus-visible {
  outline: none;
}

/* §2.1 `Filled=Off` — placeholder showing. */
.field__input::placeholder,
.field__textarea::placeholder {
  color: var(--color-content-placeholder);
}
.field__select[data-filled="false"] {
  color: var(--color-content-placeholder);
}

.field__textarea {
  /* §2.1 `Text Area` keeps the same 8px slot padding; height is content-led.
     The DS exposes `Show Resizing` and a resizer part (§2.3) — plain text
     entry does not need the RTE, per the ticket's change from RTE to plain
     text, so this is a bare textarea. */
  min-block-size: 96px;
  resize: vertical;
}

/* --- The L slot ----------------------------------------------------------
   §2.1 gives `Input / Default / Base` three slots — L, TXT, R — and the L slot
   is what the Videos filter bar's Search field uses (`Body / Videos / Page`,
   node 23304:960021). Geometry from that frame: a 40px square box holding a
   16px glyph, with the TXT slot then losing its own leading padding so the
   text starts at a single 40px inset rather than 48. */
.field__lead {
  display: flex;
  flex: none;
  align-self: stretch;
  align-items: center;
  justify-content: center;
  /* TODO(tokens): size not built — DESIGN.md §12.4. Matches the 40px control. */
  inline-size: 40px;
  color: var(--color-content-secondary);
}

.field__control:has(.field__lead) .field__input {
  padding-inline-start: 0;
}

/* --- Select — the R slot carries the caret ------------------------------- */
.field__control--select {
  position: relative;
}

.field__select {
  appearance: none;
  /* Room for the caret in the R slot: 20px glyph + `space/xs` either side. */
  padding-inline-end: calc(var(--space-xs) * 2 + 20px);
  cursor: pointer;
}

.field__caret {
  position: absolute;
  inset-inline-end: var(--space-xs);
  pointer-events: none;
  color: var(--color-content-secondary);
}

/* --- Error=On — §2.1 ---------------------------------------------------- */
.field[data-invalid="true"] .field__control {
  border-color: var(--color-border-danger-default);
}
.field[data-invalid="true"] .field__control:hover {
  border-color: var(--color-border-danger-hover);
}
/* §2 F5 implemented: the danger border stays and focus is still visible,
   because the ring comes from `border/focus` at the container. */
.field[data-invalid="true"] .field__control:focus-within {
  border-color: var(--color-border-danger-default);
  border-width: var(--shape-focus-width);
  outline: var(--shape-focus-width) solid var(--color-border-focus);
  outline-offset: var(--shape-focus-offset);
}

/* --- Disabled — §2.1 ---------------------------------------------------- */
.field__control:has(:disabled) {
  background: var(--color-solid-disabled);
  border-color: var(--color-border-default);
}
.field__input:disabled,
.field__select:disabled,
.field__textarea:disabled {
  /* §2 F4 implemented: `content/disabled`, not `content/primary`. */
  color: var(--color-content-disabled);
  cursor: default;
}

/* --- Input / Caption — §2.3 --------------------------------------------- */
.field__caption {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  color: var(--color-content-secondary);
  font-size: var(--font-body-sm-size);
  line-height: var(--font-body-sm-line-height);
}

/* §2.3 notes the caption's own colour is neutral and "the error colouring is
   applied by the consumer" — this is that consumer. §2 F2: `content/danger`,
   never the local `red/500` #ea0b16. */
.field__caption--error {
  color: var(--color-content-danger);
}

/* --- Read-only profile rows (Step 2) ------------------------------------
   Not a DS set: Step 2 only confirms values, it does not edit them, so a
   disabled `Input` would be wrong (it would read as a broken control). A
   definition list on the sunken surface reads as data, not as input. */
.field-readout {
  display: grid;
  gap: var(--space-xs) var(--space-md);
  margin: 0;
  padding: var(--space-md);
  background: var(--color-surface-sunken);
  border-radius: var(--shape-radius-card);
}
@media (min-width: 480px) {
  .field-readout {
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  }
}
.field-readout__term {
  margin: 0;
  color: var(--color-content-secondary);
  font-size: var(--font-body-sm-size);
  line-height: var(--font-body-sm-line-height);
}
.field-readout__value {
  margin: 0;
  color: var(--color-content-primary);
  font-size: var(--font-body-md-size);
  line-height: var(--font-body-md-line-height);
  font-weight: var(--font-weight-medium);
}

/* Same reason as .btn[hidden] in button.css: `display: flex` above outranks
   the UA's `[hidden]` rule. Both of these are load-bearing, not defensive —
   the ticket hides Medical group outright for a single-group user, and the
   error caption only exists once validation has actually failed. */
.field[hidden],
.field__caption[hidden] {
  display: none;
}
