:host {
  --_height: var(--input-container-height-md);
  --_padding-inline: var(--input-container-padding-inline-md);
  --_gap: var(--input-container-gap-md);
  --_radius: var(--input-container-border-radius);
  --_border-width-default: var(--input-container-border-width-default);
  --_border-width-emphasized: var(--input-container-border-width-emphasized);
  --_focus-ring-width: var(--input-container-focus-ring-width);
  --_transition-duration: var(--input-container-transition-duration);
  --_transition-easing: var(--input-container-transition-timing-function);

  --_control-font-size: var(--input-control-font-size-md);
  --_control-line-height: var(--input-control-line-height-md);
  --_icon-size: var(--input-icon-size-md);

  --_bg: var(--input-default-background-default);
  --_text: var(--input-default-text-default);
  --_text-placeholder: var(--input-default-text-placeholder);
  --_border-color: var(--input-default-border-default);
  --_border-color-hover: var(--input-default-border-hover);
  --_border-color-focus: var(--input-default-border-focus);
  --_focus-ring-color: var(--input-default-focus-ring);
  --_assistive-color: var(--input-assistive-color-default);

  display: flex;
  flex-direction: column;
  gap: var(--input-field-gap);
  inline-size: 100%;
  font-family: var(--input-control-font-family);
  color: var(--_text);
}

:host([size='lg']) {
  --_height: var(--input-container-height-lg);
  --_padding-inline: var(--input-container-padding-inline-lg);
  --_gap: var(--input-container-gap-lg);
  --_control-font-size: var(--input-control-font-size-lg);
  --_control-line-height: var(--input-control-line-height-lg);
  --_icon-size: var(--input-icon-size-lg);
}

/* ---------- Variant token overrides ---------- */
/*
 * Each named variant remaps the local custom properties to its token bundle.
 * Borders for warning/destructive/success use the same semantic color across
 * default / hover / focus per Figma (var-color shift would over-signal state).
 */
:host(.variant-warning) {
  --_border-color: var(--input-warning-border-default);
  --_border-color-hover: var(--input-warning-border-hover);
  --_border-color-focus: var(--input-warning-border-focus);
  --_focus-ring-color: var(--input-warning-focus-ring);
  --_assistive-color: var(--input-assistive-color-warning);
}

:host(.variant-destructive) {
  --_border-color: var(--input-destructive-border-default);
  --_border-color-hover: var(--input-destructive-border-hover);
  --_border-color-focus: var(--input-destructive-border-focus);
  --_focus-ring-color: var(--input-destructive-focus-ring);
  --_assistive-color: var(--input-assistive-color-error);
}

:host(.variant-success) {
  --_border-color: var(--input-success-border-default);
  --_border-color-hover: var(--input-success-border-hover);
  --_border-color-focus: var(--input-success-border-focus);
  --_focus-ring-color: var(--input-success-focus-ring);
  --_assistive-color: var(--input-assistive-color-success);
}

/* ---------- Label ---------- */

.label {
  display: flex;
  align-items: center;
  gap: var(--input-label-gap);
  font-family: var(--input-label-font-family);
  font-size: var(--input-label-font-size);
  line-height: var(--input-label-line-height);
  font-weight: var(--input-label-font-weight);
  color: var(--input-label-color-default);
  inline-size: 100%;
  min-inline-size: 0;
}

.label-text {
  display: block;
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.required-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--input-label-required-mark-size);
  block-size: var(--input-label-required-mark-size);
  color: var(--input-label-required-mark-color);
  font-weight: var(--input-control-font-weight);
  line-height: 1;
}

:host(.is-disabled) .label {
  color: var(--input-label-color-disabled);
}

:host(.is-disabled) .required-mark {
  color: var(--input-label-color-disabled);
}

/*
 * Read-only is "visible but not editable" — label stays full-contrast
 * (unlike disabled which dims the label too).
 */

/* Hide the label row entirely when no text and no slotted content is present. */
:host(:not(.has-label)) .label {
  display: none;
}

/* ---------- Control row ---------- */

.control {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--_gap);
  block-size: var(--_height);
  padding-inline: var(--_padding-inline);
  background-color: var(--_bg);
  /* A Figma stroke sits inside the frame and moves nothing (132:3424), while a
     CSS border would push the icons and the text a pixel further in. An outline
     pulled inside the box keeps the design's geometry. */
  border: 0;
  outline: var(--_border-width-default) solid var(--_border-color);
  outline-offset: calc(-1 * var(--_border-width-default));
  border-radius: var(--_radius);
  transition:
    outline-color var(--_transition-duration) var(--_transition-easing),
    box-shadow var(--_transition-duration) var(--_transition-easing),
    background-color var(--_transition-duration) var(--_transition-easing);
}

/* Emphasis ring overlay.
   The inset ring that stands in for Figma's 2px border lives on this pseudo
   element, not on `.control` itself: an autofilled `.native` paints an opaque
   `-webkit-box-shadow` fill over the control's own background and would clip
   the ring's top and bottom edges. The overlay paints after the native input,
   so the ring stays whole. The frame's own stroke is an outline pulled inside
   the box, so this spans the same box and carries the emphasised width whole
   rather than the difference. */
.control::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: var(--_radius);
  pointer-events: none;
  transition: box-shadow var(--_transition-duration) var(--_transition-easing);
}

:host(:not(.is-disabled):not(.is-readonly):not(.is-focused):hover) .control {
  outline-color: var(--_border-color-hover);
}

/* Inset shadow simulates Figma's 2px border thickening on hover without shifting content. */
:host(:not(.is-disabled):not(.is-readonly):not(.is-focused):hover) .control::after {
  box-shadow: inset 0 0 0 var(--_border-width-emphasized) var(--_border-color-hover);
}

:host(.is-focused:not(.is-disabled):not(.is-readonly)) .control {
  outline-color: var(--_border-color-focus);
  /* The outer focus ring is drawn outside the control, where the native input
     cannot reach it — it stays on `.control`. */
  box-shadow: 0 0 0 var(--spacing-4) var(--_focus-ring-color);
}

:host(.is-focused:not(.is-disabled):not(.is-readonly)) .control::after {
  box-shadow: inset 0 0 0 var(--_border-width-emphasized) var(--_border-color-focus);
}

:host(.is-readonly) .control {
  outline-color: var(--input-default-border-read-only);
  cursor: default;
}

/* Disabled / read-only recolor the private vars rather than painting
   `.control` directly: `.native:-webkit-autofill` fills the control with
   `var(--_bg)` and tints text with `var(--_text)`, so a state that only
   overrode `.control` would be repainted with the enabled colors as soon as
   the browser autofilled the field. Driving the vars keeps every surface --
   control background, autofill fill and text -- on one source of truth. */
:host(.is-disabled) {
  --_bg: var(--input-default-background-disabled);
  --_text: var(--input-default-text-disabled);
}

:host(.is-readonly) {
  --_bg: var(--input-default-background-read-only);
}

:host(.is-disabled) .control {
  outline-color: var(--input-default-border-disabled);
  cursor: not-allowed;
}

/* ---------- Loading state ----------
 * Loading composes on top of the variant + focus tokens — when active,
 * the trailing slot icon is replaced by an inline spinner and the input
 * itself becomes uninteractive without losing its visual identity.
 */
:host(.is-loading) .native {
  pointer-events: none;
  opacity: var(--input-control-loading-opacity);
}

:host(.is-loading) .control-spinner {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  inline-size: var(--_icon-size);
  block-size: var(--_icon-size);
  color: var(--input-icon-color-loading);
}

/* Hide the trailing icon slot while loading — spinner takes its place. */
:host(.is-loading) .control-icon-end {
  display: none;
}

/* ---------- Icon slots ---------- */

.control-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  inline-size: var(--_icon-size);
  block-size: var(--_icon-size);
  color: var(--input-icon-color-default);
}

.control-spinner {
  display: none;
}

:host(.is-disabled) .control-icon {
  color: var(--input-icon-color-disabled);
}

:host(:not(.has-icon-start)) .control-icon-start,
:host(:not(.has-icon-end):not(.is-loading)) .control-icon-end {
  display: none;
}

::slotted([slot='icon-start']),
::slotted([slot='icon-end']) {
  color: inherit;
}

/* ---------- Clear button ----------
 * Trailing convenience affordance shown while the field holds a value
 * (opt-in via `clearable`). Kept out of the tab order — clearing is a mouse /
 * touch shortcut; keyboard users clear with select-all + delete.
 */
.control-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  inline-size: var(--_icon-size);
  block-size: var(--_icon-size);
  padding: 0;
  margin: 0;
  border: 0;
  background: transparent;
  border-radius: var(--input-clear-button-border-radius);
  color: var(--input-clear-button-color-default);
  cursor: pointer;
  transition:
    background-color var(--_transition-duration) var(--_transition-easing),
    color var(--_transition-duration) var(--_transition-easing);
}

.control-clear:hover {
  color: var(--input-clear-button-color-hover);
  background-color: var(--input-clear-button-background-hover);
}

.control-clear:focus-visible {
  outline: var(--_border-width-emphasized) solid var(--_border-color-focus);
  outline-offset: var(--border-width-2);
}

.control-clear mud-icon {
  inline-size: var(--input-clear-button-size-md);
  block-size: var(--input-clear-button-size-md);
}

:host([size='lg']) .control-clear mud-icon {
  inline-size: var(--input-clear-button-size-lg);
  block-size: var(--input-clear-button-size-lg);
}

/* ---------- Native input ---------- */

.native {
  flex: 1 1 auto;
  min-inline-size: 0;
  inline-size: 100%;
  block-size: 100%;
  padding: 0;
  margin: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font-family: inherit;
  font-size: var(--_control-font-size);
  line-height: var(--_control-line-height);
  font-weight: var(--input-control-font-weight);
  outline: none;
  appearance: none;
  -webkit-appearance: none;
  text-overflow: ellipsis;
}

.native::placeholder {
  color: var(--_text-placeholder);
  opacity: 1;
}

.native:disabled {
  color: var(--input-default-text-disabled);
  cursor: not-allowed;
  /* Webkit otherwise dims the input on top of our token-driven disabled color. */
  -webkit-text-fill-color: var(--input-default-text-disabled);
}

.native:disabled::placeholder {
  color: var(--input-default-text-disabled);
  -webkit-text-fill-color: var(--input-default-text-disabled);
}

.native[readonly] {
  cursor: default;
}

/* Suppress browser default focus ring — the host handles focus visuals. */
.native:focus,
.native:focus-visible {
  outline: none;
}

/* WebKit-only override: paints the entire control surface with our themed
   background so the engine's yellow autofill fill cannot leak through. */
.native:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 var(--spacing-120) var(--_bg) inset;
  -webkit-text-fill-color: var(--_text);
}

/* ---------- Assistive (helper / error) ---------- */

.assistive {
  display: flex;
  align-items: flex-start;
  gap: var(--input-assistive-gap-default);
  font-family: var(--input-assistive-font-family);
  font-size: var(--input-assistive-font-size);
  line-height: var(--input-assistive-line-height);
  font-weight: var(--input-assistive-font-weight);
  color: var(--_assistive-color);
  inline-size: 100%;
  min-inline-size: 0;
}

.assistive-error {
  gap: var(--input-assistive-gap-error);
  color: var(--input-assistive-color-error);
}

.assistive-icon {
  flex-shrink: 0;
  inline-size: var(--input-assistive-icon-size);
  block-size: var(--input-assistive-icon-size);
  margin-block-start: 0;
}

.assistive-text {
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow: hidden;
  /* Truncate to two lines, per Figma edge-case guidance. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  text-overflow: ellipsis;
}

/* ---------- prefers-reduced-motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .control,
  .control::after {
    transition: none;
  }
}
