/* ===========================================================================
 * FM01 Field · FM02 TextInput · FM03 Textarea · FM04 Search.
 *
 * Every input is --radius-sm, including the search field. The history-log mock
 * draws that one as a pill and §5 calls it an oversight; D17 unified it. There
 * is now no input in the system with a different radius, which is the point.
 *
 * The resting fill is `transparent` — the 1px border at 18% white does all the
 * work. Adding a fill would put a second, competing edge on every field.
 * ======================================================================== */

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

.ui-field__label {
  font-size: var(--type-body-size);
  line-height: var(--type-body-leading);
  font-weight: var(--font-weight-semibold);
  color: var(--text-primary);
}

.ui-field--disabled .ui-field__label { color: var(--text-label-disabled); }

.ui-field__required { color: var(--text-gold); margin-left: var(--space-1); }

/* Helper and counter share one row: helper left, counter right. On a textarea
   the counter is the thing being watched, so it is monospaced — a proportional
   digit changes width as it counts and the row jitters. */
.ui-field__footer {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
}

.ui-field__helper {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
  color: var(--text-tertiary);
}

.ui-field__helper .icon { margin-top: var(--space-1); }

.ui-field__counter {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
  color: var(--text-tertiary);
  flex: none;
}

.ui-field__counter.is-over { color: var(--danger-text); }

/* FB06 — the inline validation message. Brick, 12px, with a leading alert
   icon, sitting directly under the control it belongs to. */
.ui-field__error {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
  color: var(--danger);
}

.ui-field__error .icon { margin-top: var(--space-1); }

/* --- the control itself ------------------------------------------------- */
.ui-input {
  width: 100%;
  height: var(--control-height);
  padding: 0 var(--space-3);
  background: var(--surface-input);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--type-body-lg-size);
  line-height: var(--type-body-lg-leading);
  transition: border-color var(--duration-fast) var(--easing-standard),
              outline-color var(--duration-fast) var(--easing-standard),
              background var(--duration-fast) var(--easing-standard);
}

.shell--player .ui-input { height: var(--control-height-mobile); }

/* A date input in WebKit has an intrinsic minimum width that beats
   `width: 100%` inside the field's flex column, so on iOS Date of Birth ran off
   the right edge. Without the platform appearance it sizes like any input, and
   its value sits on the left like every other field's. */
.ui-input[type="date"] {
  /* The picker's calendar icon is drawn by the platform; dark, so it is light. */
  color-scheme: dark;
  -webkit-appearance: none;
  appearance: none;
  display: block;
  min-width: 0;
  max-width: 100%;
}

.ui-input[type="date"]::-webkit-date-and-time-value { text-align: left; }

.ui-input::placeholder { color: var(--text-placeholder); }

.ui-input:hover:not(:disabled) { border-color: var(--border-raised); }

/* Focus on an input is NOT the offset ring the buttons use. The field already
   has a border in exactly the right place, so focus recolours that border to
   full gold and lays a soft translucent halo flush against it, which reads as
   the field lighting up rather than as a ring drawn around it (D30).

   `outline-offset: 0` is what makes it a halo rather than a ring — it sits
   against the border instead of clear of it. */
.ui-input:focus,
.ui-input.is-focus {
  border-color: var(--gold-100);
  outline: var(--focus-halo-width) solid var(--gold-halo);
  outline-offset: 0;
}

.ui-input.is-invalid,
.ui-input[aria-invalid="true"] {
  border-color: var(--danger);
  background: var(--danger-field-wash);
}

.ui-input.is-invalid:focus,
.ui-input[aria-invalid="true"]:focus {
  border-color: var(--danger);
  outline-color: var(--danger-wash);
}

.ui-input:disabled,
.ui-input.is-disabled {
  border-color: var(--border-input-disabled);
  background: var(--surface-input-disabled);
  color: var(--text-disabled);
  cursor: not-allowed;
}

.ui-input:disabled::placeholder { color: var(--text-disabled); }

/* --- FM03 Textarea ------------------------------------------------------ */
.ui-textarea {
  height: auto;
  min-height: var(--textarea-height);
  padding: var(--space-3);
  resize: vertical;
}

/* --- FM04 Search — the input plus a leading icon. The icon is absolutely
       positioned rather than in a flex row so the <input> keeps its full
       clickable width; clicking the padding still focuses the field. ----- */
.ui-search { position: relative; display: block; }

.ui-search__icon {
  position: absolute;
  left: var(--space-3);
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-placeholder);
  pointer-events: none;
}

.ui-search .ui-input { padding-left: var(--space-10); }

.ui-search:focus-within .ui-search__icon { color: var(--gold-100); }

/* --- FM11 File upload ---------------------------------------------------
 * New to the system, and the first file input in the product. The mocks name
 * "Upload Team List" as an action and draw nothing, so every state here comes
 * from the library's own rules rather than from a frame.
 *
 * A DASHED border, which is the one border treatment nothing else in the
 * library uses. A wash at this size reads as a card, and a card does not
 * invite a drop. The dash is what makes the region legible as "put something
 * here" without a colour or a shadow doing the work.
 * --------------------------------------------------------------------- */
.ui-file { display: block; }

/* The real input. Present, focusable and submitted — moved out of sight, never
   display:none, which would take it out of the tab order and stop the label
   from operating it. */
.ui-file__input {
  position: absolute;
  width: var(--border-width);
  height: var(--border-width);
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.ui-file__dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-8) var(--space-5);
  border: var(--border-width-emphasis) dashed var(--border-empty);
  border-radius: var(--radius-sm);
  background: var(--surface-input);
  color: var(--text-secondary);
  text-align: center;
  cursor: pointer;
}

.ui-file__glyph { color: var(--text-placeholder); }

.ui-file__action { color: var(--text-gold); font-weight: var(--font-weight-semibold); }
.ui-file__or { color: var(--text-tertiary); }

.ui-file__filename {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
  color: var(--text-primary);
}

.ui-file__hint {
  margin-top: var(--space-2);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
  color: var(--text-tertiary);
}

/* D28: hover changes the FILL, never the opacity. */
.ui-file__dropzone:hover,
.ui-file.is-hover .ui-file__dropzone {
  background: var(--gold-wash-hover);
  border-color: var(--gold-rest);
}

.ui-file__dropzone:hover .ui-file__glyph,
.ui-file.is-hover .ui-file__dropzone .ui-file__glyph { color: var(--gold-100); }

/* The ring goes on the LABEL, driven by focus on the input it belongs to —
   the input itself is clipped out of sight, so a ring on it would be invisible
   and the control would appear to swallow the keyboard. */
.ui-file__input:focus-visible + .ui-file__dropzone,
.ui-file.is-focus .ui-file__dropzone {
  outline: var(--focus-ring-outline);
  outline-offset: var(--focus-ring-offset);
  outline-color: var(--focus-colour-neutral);
}

/* Dragging is a stronger read than hover: the file is already in the air and
   the zone has to say it will be caught. */
.ui-file.is-dragging .ui-file__dropzone {
  background: var(--gold-wash-selected);
  border-color: var(--gold-100);
  border-style: solid;
}

.ui-file.is-dragging .ui-file__glyph { color: var(--gold-100); }

/* Brick, never a conventional red (D27). */
.ui-file--invalid .ui-file__dropzone {
  border-color: var(--danger-border);
  background: var(--danger-field-wash);
}

/* The ONLY state that changes opacity (D28). */
.ui-file--disabled .ui-file__dropzone {
  opacity: var(--opacity-disabled);
  cursor: not-allowed;
}

.ui-file--disabled .ui-file__dropzone:hover {
  background: var(--surface-input);
  border-color: var(--border-empty);
}

/* ---------------------------------------------------------------------------
 * FM12 — Colour input. A native colour well beside a hex text field.
 * ------------------------------------------------------------------------- */

.ui-colour-input {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* The field takes the slack; the well stays square. */
.ui-colour-input .ui-colour-input__hex {
  flex: 1 1 auto;
  min-width: 0;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  text-transform: uppercase;
}

/* The well is styled completely — only the picker dialog it opens belongs to
   the operating system. Every browser draws the swatch inside its own padded
   chrome, so the vendor pseudo-elements below strip that back to the colour
   itself; without them the swatch is a small square floating in a white box. */
.ui-colour-input__swatch {
  flex: 0 0 auto;
  width: var(--control-height);
  height: var(--control-height);
  padding: 0;
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-sm);
  background: var(--surface-input);
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}

.shell--player .ui-colour-input__swatch {
  width: var(--control-height-mobile);
  height: var(--control-height-mobile);
}

.ui-colour-input__swatch::-webkit-color-swatch-wrapper { padding: 0; }

.ui-colour-input__swatch::-webkit-color-swatch {
  border: none;
  border-radius: var(--radius-control);
}

.ui-colour-input__swatch::-moz-color-swatch {
  border: none;
  border-radius: var(--radius-control);
}

.ui-colour-input__swatch:hover:not(:disabled) { border-color: var(--border-raised); }

/* One outline ring, gold on a neutral control (D30). Never a box-shadow. */
.ui-colour-input__swatch:focus-visible {
  outline: var(--focus-ring-outline);
  outline-offset: var(--focus-ring-offset);
  outline-color: var(--focus-colour-neutral);
}

/* `<input type="color">` has no empty state — it falls back to black, which
   reads as "black is chosen". The dashed border is the same treatment the file
   dropzone and the empty state use for "nothing here yet", so an unset colour
   looks unset rather than dark. */
.ui-colour-input--unset .ui-colour-input__swatch {
  border-style: dashed;
  border-color: var(--border-empty);
}

/* The ONLY state that changes opacity (D28). */
.ui-colour-input--disabled .ui-colour-input__swatch {
  opacity: var(--opacity-disabled);
  cursor: not-allowed;
}

/* --- FM01 Field: the save state (D170) -------------------------------------
 * Beside the label, so it is read with the field it belongs to. Words, not a
 * spinner or a tick alone: "Saving…", "Saved", or what went wrong. Saved is
 * moss; an error is brick, as every error is (D27). */
.ui-field__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.ui-field__status {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-leading);
  color: var(--text-tertiary);
  text-align: right;
}

.ui-field__status[data-state="saved"] { color: var(--success); }
.ui-field__status[data-state="error"] { color: var(--danger); }

.ui-field__retry {
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-gold);
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

.ui-field__retry:focus-visible {
  outline: var(--focus-ring-outline);
  outline-color: var(--focus-colour-neutral);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-sm);
}
