/**
 * wp-admin text inputs, selects and textareas, styled from WordPress
 * Design System tokens.
 *
 * Target: visual parity with the `@wordpress/ui` input primitive
 * (packages/ui/src/form/primitives/input-layout/style.module.css), which is the
 * purest token expression of a field in the design system. Values come from
 * there; the selectors below are hand-authored against the admin's markup.
 *
 * Selector list mirrors the one in wp-admin/css/forms.css so the same set of
 * controls is covered — no more, no less.
 *
 * NO `!important` IN THIS FILE. See 99-overrides.css for the one exception and why.
 */

@layer wpds-overrides, wp-legacy, wpds;

@layer wpds {

	/* -----------------------------------------------------------------------
	   Base — shared by text inputs, select and textarea
	   ----------------------------------------------------------------------- */

	input[type="text"],
	input[type="password"],
	input[type="color"],
	input[type="date"],
	input[type="datetime"],
	input[type="datetime-local"],
	input[type="email"],
	input[type="month"],
	input[type="number"],
	input[type="search"],
	input[type="tel"],
	input[type="time"],
	input[type="url"],
	input[type="week"],
	select,
	textarea {
		box-sizing: border-box;
		border: var(--wpds-border-width-xs) solid var(--wpds-color-stroke-interactive-neutral);
		border-radius: var(--wpds-border-radius-sm);
		background-color: var(--wpds-color-background-interactive-neutral);
		color: var(--wpds-color-foreground-interactive-neutral);
		box-shadow: none;
		font-family: var(--wpds-typography-font-family-body);
		/*
		 * NO font-size. WordPress sets `input, select, textarea, button { font-size:
		 * inherit }`, so a control takes the size of whatever contains it — which
		 * is why a settings form reads coherently, with label, field and help text
		 * all at one size. Pinning a size here broke that: the label stayed at the
		 * container's size while the field it belongs to shrank to 13px.
		 *
		 * Inheriting keeps a control correct in every context without us having to
		 * know what those contexts are. WordPress also handles the mobile case, raising
		 * inputs to 16px below 782px so iOS does not zoom on focus.
		 */

		/*
		 * `normal`, not `1`. The `@wordpress/ui` input primitive uses `line-height: 1`,
		 * but it sets it on a wrapper that lays out a separate inner `<input>`, where
		 * the text has room regardless. wp-admin has no wrapper: the declaration lands
		 * on the bare control, and a line box exactly as tall as the font is shorter
		 * than the font's own ascender-plus-descender, so descenders are clipped by the
		 * control's chrome — visibly on `<select>` in Firefox, and on number fields in
		 * Settings > Media.
		 *
		 * `normal` lets the font's metrics size the line box, which cannot clip, and
		 * unlike a pixel value it does not compete with the contextual heights
		 * WordPress sets per control. Worth raising against the primitive too: `1` is
		 * only safe there because of the markup around it.
		 */
		line-height: normal;
	}

	/* -----------------------------------------------------------------------
	   Sizing — text inputs and select get a fixed height; textarea does not
	   ----------------------------------------------------------------------- */

	input[type="text"],
	input[type="password"],
	input[type="date"],
	input[type="datetime"],
	input[type="datetime-local"],
	input[type="email"],
	input[type="month"],
	input[type="number"],
	input[type="search"],
	input[type="tel"],
	input[type="time"],
	input[type="url"],
	input[type="week"] {
		/* No height — see the note in 10-button.css. WordPress's default is already 40px
		   and its contextual rules must keep winning. */
		padding: 0 var(--wpds-dimension-padding-md);
	}

	/*
	 * Select needs asymmetric padding, because WordPress draws the dropdown arrow as a
	 * background image at the trailing edge and the text has to clear it.
	 *
	 * WordPress reserves exactly the arrow's own width (24px for a 16px arrow inset
	 * 8px), so the text ends precisely where the arrow begins and there is no
	 * gutter at all. React's SelectControl reserves the icon PLUS a trailing
	 * gutter mirroring the leading one:
	 *
	 *     paddingLeft:  controlPaddingX          // 12
	 *     paddingRight: controlPaddingX + 18     // chevronIconSize
	 *
	 * This adopts that formula rather than inventing a number, so the two are the
	 * same construction rather than coincidentally similar.
	 *
	 * The 18px is deliberately not a token. The icon set is drawn and hinted at
	 * 24x24 and, being fill-based, scales badly to arbitrary sizes; 18 is 75% of
	 * 24, picked to interpolate cleanly. Mirroring it keeps the admin and the
	 * component in step.
	 *
	 * Logical properties, so this follows the arrow when WordPress's RTL stylesheet
	 * flips it to the leading edge.
	 */
	select {
		/*
		 * Only the TRAILING padding, not the shorthand. WordPress narrows the leading
		 * padding contextually (`.wp-core-ui .tablenav select` uses 8px), and a
		 * shorthand here would flatten that along with everything else. Setting
		 * one side leaves WordPress's contextual value on the other intact, and the
		 * arrow still gets its gutter in every context.
		 *
		 * No height, for the reason given in 10-button.css.
		 */
		padding-inline-end: calc(var(--wpds-dimension-padding-md) + 18px);
	}

	textarea {
		padding: var(--wpds-dimension-padding-sm) var(--wpds-dimension-padding-md);
		line-height: var(--wpds-typography-line-height-md);
	}

	/* -----------------------------------------------------------------------
	   Placeholder
	   ----------------------------------------------------------------------- */

	input::placeholder,
	textarea::placeholder {
		color: var(--wpds-color-foreground-interactive-neutral-weak);
		opacity: 1;
	}

	/* -----------------------------------------------------------------------
	   Hover — the admin has no hover state; the design system darkens the border.

	   Excluded from disabled and readonly fields. Without the :not() the hover
	   rule outranks the disabled rule: an attribute selector plus a pseudo-class
	   is (0,2,1), while `input:disabled` is only (0,1,1), so hovering a disabled
	   field would light up its border as if it were editable.
	   ----------------------------------------------------------------------- */

	input[type="text"]:hover,
	input[type="password"]:hover,
	input[type="date"]:hover,
	input[type="datetime"]:hover,
	input[type="datetime-local"]:hover,
	input[type="email"]:hover,
	input[type="month"]:hover,
	input[type="number"]:hover,
	input[type="search"]:hover,
	input[type="tel"]:hover,
	input[type="time"]:hover,
	input[type="url"]:hover,
	input[type="week"]:hover,
	select:hover,
	textarea:hover {
		border-color: var(--wpds-color-stroke-interactive-neutral-active);
	}

	/* Disabled fields keep the disabled border on hover. */
	input:is([type="text"], [type="password"], [type="color"], [type="date"], [type="datetime"], [type="datetime-local"], [type="email"], [type="month"], [type="number"], [type="search"], [type="tel"], [type="time"], [type="url"], [type="week"]):disabled:hover,
	input:is([type="text"], [type="password"], [type="color"], [type="date"], [type="datetime"], [type="datetime-local"], [type="email"], [type="month"], [type="number"], [type="search"], [type="tel"], [type="time"], [type="url"], [type="week"]).disabled:hover,
	input:is([type="text"], [type="password"], [type="color"], [type="date"], [type="datetime"], [type="datetime-local"], [type="email"], [type="month"], [type="number"], [type="search"], [type="tel"], [type="time"], [type="url"], [type="week"])[aria-disabled="true"]:hover,
	select:disabled:hover,
	select.disabled:hover,
	select[aria-disabled="true"]:hover,
	textarea:disabled:hover,
	textarea.disabled:hover,
	textarea[aria-disabled="true"]:hover {
		border-color: var(--wpds-color-stroke-interactive-neutral-disabled);
	}

	/*
	 * Readonly fields keep the NORMAL border on hover — they are not disabled,
	 * their border is the normal one, and lightening it would be wrong in the
	 * other direction. They simply do not gain the hover emphasis, because the
	 * tinted background already says the value cannot be edited.
	 */
	input[readonly]:hover,
	input.readonly:hover,
	textarea[readonly]:hover,
	textarea.readonly:hover {
		border-color: var(--wpds-color-stroke-interactive-neutral);
	}

	/* -----------------------------------------------------------------------
	   Focus — outline/outline-offset, never box-shadow.
	   WordPress's ring is a box-shadow plus an accent border; both are replaced.
	   ----------------------------------------------------------------------- */

	input[type="text"]:focus,
	input[type="password"]:focus,
	input[type="color"]:focus,
	input[type="date"]:focus,
	input[type="datetime"]:focus,
	input[type="datetime-local"]:focus,
	input[type="email"]:focus,
	input[type="month"]:focus,
	input[type="number"]:focus,
	input[type="search"]:focus,
	input[type="tel"]:focus,
	input[type="time"]:focus,
	input[type="url"]:focus,
	input[type="week"]:focus,
	select:focus,
	textarea:focus {
		border-color: var(--wpds-color-stroke-interactive-neutral);
		outline: var(--wpds-border-width-focus) solid var(--wpds-color-stroke-focus);
		outline-offset: var(--wpds-border-width-focus);
		box-shadow: none;
	}

	/*
	 * Invalid required fields take an error-coloured ring, so the ring and the
	 * border agree. The border itself is set in 99-overrides.css, because
	 * forms.css marks it `!important`. Selectors follow forms.css's own
	 * `.form-invalid` rules.
	 */
	.form-invalid .form-required:focus,
	.form-invalid.form-required input:focus,
	.form-invalid.form-required select:focus {
		outline-color: var(--wpds-color-stroke-interactive-error);
	}

	/* -----------------------------------------------------------------------
	   Disabled and readonly

	   Inputs are scoped to the text-like types this file styles. A bare
	   `input:disabled` also matches file, range and button inputs, and from
	   this layer it would override the transparent background forms.css gives
	   file and range controls on purpose.

	   The type list also carries the specificity these rules need. A focused
	   `aria-disabled` field is still focusable, and without the attribute
	   selectors here `input[type="text"]:focus` would outrank the disabled
	   rule and hand the field back its enabled border.
	   ----------------------------------------------------------------------- */

	input:is([type="text"], [type="password"], [type="color"], [type="date"], [type="datetime"], [type="datetime-local"], [type="email"], [type="month"], [type="number"], [type="search"], [type="tel"], [type="time"], [type="url"], [type="week"]):disabled,
	input:is([type="text"], [type="password"], [type="color"], [type="date"], [type="datetime"], [type="datetime-local"], [type="email"], [type="month"], [type="number"], [type="search"], [type="tel"], [type="time"], [type="url"], [type="week"]).disabled,
	input:is([type="text"], [type="password"], [type="color"], [type="date"], [type="datetime"], [type="datetime-local"], [type="email"], [type="month"], [type="number"], [type="search"], [type="tel"], [type="time"], [type="url"], [type="week"])[aria-disabled="true"],
	select:disabled,
	select.disabled,
	select[aria-disabled="true"],
	textarea:disabled,
	textarea.disabled,
	textarea[aria-disabled="true"] {
		background-color: var(--wpds-color-background-interactive-neutral-disabled);
		border-color: var(--wpds-color-stroke-interactive-neutral-disabled);
		color: var(--wpds-color-foreground-interactive-neutral-disabled);
		box-shadow: none;
	}

	/*
	 * The dropdown arrow is a background image with its colour baked into the
	 * data URI, so it cannot follow a token or `currentColor`. WordPress swaps in a
	 * grey arrow for `select.disabled` and `select:disabled`, but leaves
	 * `select[aria-disabled="true"]` with only `cursor: default` — no visual
	 * disabled treatment at all.
	 *
	 * Since the rules above do give an aria-disabled field the disabled box, the
	 * arrow has to follow, or it stays black against a greyed control. This
	 * repeats WordPress's own grey arrow verbatim so all three disabled forms render
	 * identically; the colour is WordPress's #a0a5aa rather than the disabled token,
	 * because matching the other two matters more than matching the palette
	 * while the value is trapped inside a data URI.
	 *
	 * Replacing dashicons with the stroke-based set removes this entirely: a
	 * masked icon takes `currentColor` and needs no second copy.
	 */
	select[aria-disabled="true"] {
		background-image: url(data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23a0a5aa%22%2F%3E%3C%2Fsvg%3E);
	}

	input.readonly,
	input[readonly],
	textarea.readonly,
	textarea[readonly] {
		background-color: var(--wpds-color-background-surface-neutral-weak);
	}
}
