/* -- Input component ------------------------------------------- */

@layer components {
  .input {
    /* border-box is load-bearing for the shared field ladder: the UA gives
       <input> content-box, so `height` would otherwise exclude the 2px frame
       and render 2px taller than the border-box fields (select, button-based
       triggers). With it, every declared height IS the rendered box.
       The unsized default IS the ladder's md step (2.25rem = 36px) - same
       height, padding and font as [data-size="md"] below, so an unlabeled
       field and an explicit md field are the same control. */
    box-sizing: border-box;
    height: 2.25rem;
    width: 100%;
    border: 1px solid var(--input);
    border-radius: var(--radius-md);
    background: var(--background);
    padding: 0 0.75rem;
    font-size: 0.875rem;
    font-family: var(--font-sans);
    color: var(--foreground);
    outline: none;
    box-shadow: var(--shadow-xs);
    transition: border-color 150ms, box-shadow 150ms;

    &:focus {
      border-color: var(--ring);
      box-shadow: 0 0 0 2px oklch(from var(--ring) l c h / 0.2);
    }

    &::placeholder { color: var(--muted-foreground); }

    /* -- Readonly state -------------------------------------- */
    /* :not(:disabled) is load-bearing: a disabled input ALSO matches
       :read-only, and this rule's specificity (class + pseudo + :not attr)
       outranks the plain :disabled below - without the exclusion, disabled
       controls would render with the readonly look (0.7/default). */
    &:read-only:not([type="file"], :disabled) {
      background: var(--muted);
      cursor: default;
      opacity: 0.7;

      &:focus {
        border-color: var(--input);
        box-shadow: var(--shadow-xs);
      }
    }

    /* Disabled = legible but inert: a muted surface and muted text inside
       the full-strength border - never an opacity fade that lets the box
       dissolve into the page. */
    &:disabled {
      background-color: var(--muted);
      color: var(--muted-foreground);
      box-shadow: none;
      cursor: not-allowed;
    }

    /* -- Invalid state --------------------------------------- */
    /* WHEN a field turns red: aria-invalid="true" always (the page decided).
       The browser's own verdict (:user-invalid, i.e. after the user left a
       changed field) only counts inside a <form> - a standalone text box has
       nothing to submit, so a half-typed value is never judged - and inside
       form[data-validate="submit"] only once the page has stamped
       data-submitted on the form (a submit attempt): check when the person
       is finished, not the instant they leave the box. */
    &:is([aria-invalid="true"], :user-invalid:is(form *):not(form[data-validate="submit"]:not([data-submitted]) *)) {
      border-color: var(--destructive);

      &:focus {
        border-color: var(--destructive);
        box-shadow: 0 0 0 2px oklch(from var(--destructive) l c h / 0.2);
      }
    }

    /* -- File input ------------------------------------------ */
    &[type="file"] {
      padding: 0;
      font-size: 0.875rem;

      &::file-selector-button {
        height: 100%;
        border: none;
        border-right: 1px solid var(--input);
        background: var(--muted);
        color: var(--foreground);
        font-size: 0.875rem;
        font-weight: 500;
        font-family: var(--font-sans);
        padding: 0 0.75rem;
        margin-right: 0.75rem;
        cursor: pointer;
        transition: background 150ms;

        &:hover { background: var(--accent); }
      }
    }

    /* -- Native in-field buttons ------------------------------
       The clear "×" of type="search" and the calendar/clock icon of the
       date/time types are clickable controls INSIDE the text field - without
       this they inherit the field's text cursor and look like more text to
       type into (the file picker's button above already points). */
    &::-webkit-search-cancel-button,
    &::-webkit-calendar-picker-indicator {
      cursor: pointer;
    }

    /* -- Sizes ----------------------------------------------- */
    &[data-size="xs"] { height: 1.75rem; padding: 0 0.5rem;   font-size: 0.75rem; }
    &[data-size="sm"] { height: 2rem;    padding: 0 0.625rem; font-size: 0.8125rem; }
    &[data-size="md"] { height: 2.25rem; padding: 0 0.75rem;  font-size: 0.875rem; }
    &[data-size="lg"] { height: 2.75rem; padding: 0 1rem;     font-size: 1rem; }
    &[data-size="xl"] { height: 3.25rem; padding: 0 1.25rem;  font-size: 1.125rem; }
  }

  /* -- Input group: icons, text and buttons inside the field ---
     The GROUP draws the field frame (border, radius, shadow, focus ring,
     invalid / disabled / readonly surfaces); the .input inside goes
     frameless and fills the rest. DOM order is the placement: an addon
     before the .input sits at the start, one after it at the end - so a
     trailing copy / show-password / clear button is just markup after the
     input, and any addon width works without hand-tuned padding. */
  .input-group {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    width: 100%;
    height: 2.25rem;
    border: 1px solid var(--input);
    border-radius: var(--radius-md);
    background: var(--background);
    box-shadow: var(--shadow-xs);
    color: var(--muted-foreground);
    font-size: 0.875rem;
    transition: border-color 150ms, box-shadow 150ms;

    & > .input {
      flex: 1;
      min-width: 0;
      height: 100%;
      border: none;
      border-radius: inherit;
      background: transparent;
      box-shadow: none;
      font-size: inherit;

      &:focus { box-shadow: none; }
      &:not(:first-child) { padding-inline-start: 0.5rem; }
      &:not(:last-child) { padding-inline-end: 0.5rem; }
    }

    &:has(> .input:focus) {
      border-color: var(--ring);
      box-shadow: 0 0 0 2px oklch(from var(--ring) l c h / 0.2);
    }

    &:has(> .input:is([aria-invalid="true"], :user-invalid:is(form *):not(form[data-validate="submit"]:not([data-submitted]) *))) {
      border-color: var(--destructive);

      &:has(> .input:focus) {
        box-shadow: 0 0 0 2px oklch(from var(--destructive) l c h / 0.2);
      }
    }

    /* readonly: the group carries the muted surface (the input's own
       readonly background would stop short of the addons) */
    &:has(> .input:read-only:not(:disabled)) {
      background: var(--muted);

      & > .input { background: transparent; }
      &:has(> .input:focus) {
        border-color: var(--input);
        box-shadow: var(--shadow-xs);
      }
    }

    &:has(> .input:disabled) {
      background: var(--muted);
      box-shadow: none;
      cursor: not-allowed;

      & > .input { background: transparent; }
    }

    /* decorative icon (inline <svg> or lucide <i>) */
    & > .input-group-icon {
      flex-shrink: 0;
      width: 1rem;
      height: 1rem;
      color: var(--muted-foreground);
      pointer-events: none;

      &:first-child { margin-inline-start: 0.75rem; }
      &:last-child { margin-inline-end: 0.75rem; }
    }

    /* static text: a unit, a protocol, a domain */
    & > .input-group-text {
      flex-shrink: 0;
      white-space: nowrap;
      color: var(--muted-foreground);
      user-select: none;

      &:first-child { margin-inline-start: 0.75rem; }
      &:last-child { margin-inline-end: 0.75rem; }
    }

    /* an in-field action: copy, show/hide, clear, open a picker */
    & > .input-group-button {
      flex-shrink: 0;
      display: inline-grid;
      place-items: center;
      box-sizing: border-box;
      height: calc(100% - 0.5rem);
      aspect-ratio: 1;
      padding: 0;
      border: none;
      border-radius: var(--radius-sm);
      background: transparent;
      color: var(--muted-foreground);
      cursor: pointer;
      transition: background-color 150ms, color 150ms;

      & svg { width: 1rem; height: 1rem; }
      /* icon swaps (copy -> check, eye -> eye-off): the UA's [hidden] rule
         only covers HTML elements, so a hidden <svg> needs its own */
      & svg[hidden] { display: none; }
      &:hover { background: var(--accent); color: var(--accent-foreground); }
      &:focus-visible { outline: 2px solid var(--ring); outline-offset: 1px; }
      &:disabled { cursor: not-allowed; background: transparent; color: var(--muted-foreground); }
      &:first-child { margin-inline-start: 0.25rem; }
      &:last-child { margin-inline-end: 0.25rem; }
      & + .input-group-button { margin-inline-start: 0.125rem; }
    }

    /* -- Sizes: the same ladder as .input, set on the group ------ */
    &[data-size="xs"] { height: 1.75rem; font-size: 0.75rem; }
    &[data-size="sm"] { height: 2rem;    font-size: 0.8125rem; }
    &[data-size="md"] { height: 2.25rem; font-size: 0.875rem; }
    &[data-size="lg"] { height: 2.75rem; font-size: 1rem; }
    &[data-size="xl"] { height: 3.25rem; font-size: 1.125rem; }
  }

  /* -- Auto-growing textarea --------------------------------- */
  textarea.input {
    field-sizing: content;
    min-height: 5rem;
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
  }

  /* -- Field description ------------------------------------- */
  .field-description {
    font-size: 0.8125rem;
    color: var(--muted-foreground);
    margin: 0.375rem 0 0;
  }

  /* -- Field error ------------------------------------------- */
  .field-error {
    font-size: 0.8125rem;
    color: var(--destructive);
    margin: 0.375rem 0 0;
  }

  /* -- Accessibility ---------------------------------------- */
  @media (prefers-reduced-motion: reduce) {
    .input {
      transition: none;
    }

    .input[type="file"]::file-selector-button {
      transition: none;
    }
  }

  @media (prefers-contrast: more) {
    .input {
      border-width: 2px;
    }

    .input:disabled {
      border-color: var(--muted-foreground);
    }
  }

  @media (forced-colors: active) {
    .input {
      border-color: ButtonBorder;
      color: ButtonText;
      background: Field;
    }

    .input:focus {
      outline: 2px solid Highlight;
      outline-offset: 1px;
    }

    .input:disabled {
      opacity: 1;
      color: GrayText;
      border-color: GrayText;
    }

    .input:is([aria-invalid="true"], :user-invalid:is(form *):not(form[data-validate="submit"]:not([data-submitted]) *)) {
      border-color: LinkText;
    }

    .field-error {
      color: LinkText;
    }

    .input-group {
      border-color: ButtonBorder;
      background: Field;

      & > .input:focus { outline: none; }
      &:has(> .input:focus) { outline: 2px solid Highlight; outline-offset: 1px; }
      &:has(> .input:disabled) { border-color: GrayText; }
      & > .input-group-button { color: ButtonText; }
    }
  }
}
