:root {
	--default-color: #939393;
	--focus-color: #0080ff;
	/* valid + warning follow the page's `color-scheme` via light-dark();
	   plain values first as a fallback (dark palette) for older browsers. */
	--valid-color: #00d112;
	--warning-color: #f7b500;
	--valid-color: light-dark(#00AC0F, #00d112);
	--warning-color: light-dark(#EA7200, #f7b500);
	--invalid-color: #e60000;

	--shadow-strength: 0.75;
	--transition-duration: 0.15s;
}

/*
 * ⚠️ A11y — border contrast (WCAG 1.4.11 Non-text Contrast: 3:1 minimum).
 * Colors follow the page's `color-scheme` (which the developer sets), via
 * light-dark(). The dark palette is tuned for dark backgrounds, the light one
 * for white — approximate border/background ratios:
 *   dark  — every state clears 3:1
 *   light — --valid #00AC0F ~3.0:1, --warning #EA7200 ~3.0:1 (amber→orange);
 *           --focus, --invalid and --default also pass
 *
 * v2.2.0 — states aren't conveyed by colour alone any more (WCAG 1.4.1):
 * judged states carry a drawn icon (warning triangle, error cross, valid tick).
 *
 * Each icon rides in the input's background via a data-URI SVG — the only way
 * to paint a mark on a *bare* <input> (which can't take a foreground image, a
 * mask, or a ::before/::after). The SVGs are inlined here rather than referenced
 * as url("warning.svg"), so there's no per-input network request; each icon's
 * colours are baked in (fill + stroke chosen to read on both light and dark
 * backgrounds), so there's no palette or light-dark() to re-tint. The source
 * files live alongside this stylesheet: warning.svg, error.svg, check.svg — edit
 * those, then re-inline (URL-encode the markup) to change an icon.
 */

input {
	border: 1px solid var(--default-color);
	outline: none;
	transition: border-color var(--transition-duration) ease-out, box-shadow var(--transition-duration) ease-out;
}

/* Icon slot — single-line text fields only. Other types bring their own
   right-edge UI (date pickers, number spinners, search's clear button) or
   don't take a background sanely (checkbox, radio, range, color…); they keep
   the border-colour feedback. The state rules below only set --state-icon, which stays
   inert unless this rule turns it into a real background — that is what keeps
   stray icons off checkboxes. `:is()` (rather than `:where()`) keeps enough
   specificity that a page's own `input { padding }` reset doesn't collapse
   the reserved slot and let text run under the icon. */
input:is([type='text'], [type='email'], [type='password'], [type='tel'], [type='url'], :not([type])) {
	padding-right: 2.2rem; /* 1.2rem icon + 0.6rem edge + 0.4rem gap; constant, so no layout shift */
	background-image: var(--state-icon, none);
	background-repeat: no-repeat;
	background-position: right 0.6rem center;
	background-size: 1.2rem 1.2rem;
}

/* Keep a keyboard focus ring in forced-colors / high-contrast mode, where the
   glow (box-shadow) isn't painted. It's invisible in normal mode, so the glow
   stays the focus cue; the OS repaints this outline when forced-colors is on. */
input:focus-visible {
	outline: 2px solid transparent;
	outline-offset: 2px;
}

/* Focus + placeholder (typing hasn't started) */
input:focus:placeholder-shown {
	border-color: var(--focus-color);
	box-shadow: 0 2px 10px 0.1px color-mix(in srgb, var(--focus-color) calc(var(--shadow-strength) * 100%), transparent);
}

/* Focus but invalid input (only once the user has typed something): ⚠️ */
input:focus:invalid:not(:placeholder-shown) {
	border-color: var(--warning-color);
	box-shadow: 0 2px 10px 0.1px color-mix(in srgb, var(--warning-color) calc(var(--shadow-strength) * 100%), transparent);
	--state-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24' role='img' aria-label='Warning'%3E%3Cpath d='M12 2.4c.6 0 1.15.32 1.44.85l9 16.05c.3.52.3 1.16 0 1.68s-.84.87-1.44.87H3c-.6 0-1.15-.34-1.44-.87s-.3-1.16 0-1.68l9-16.05c.29-.53.84-.85 1.44-.85Z' fill='%23f7b500' stroke='%23EA7200' stroke-width='1.6' stroke-linejoin='round'/%3E%3Cpath d='M10.6 8a1.4 1.4 0 0 1 2.8 0l-.7 6.2a.7.7 0 0 1-1.4 0z' fill='%23222222'/%3E%3Ccircle cx='12' cy='18.1' r='1.3' fill='%23222222'/%3E%3C/svg%3E");
}

/* Unfocused invalid: ❌ */
input:not(:focus):user-invalid {
	border-color: var(--invalid-color);
	--state-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24' role='img' aria-label='Invalid input'%3E%3Cpath d='M6 6 18 18 M18 6 6 18' fill='none' stroke='%23b30000' stroke-width='4' stroke-linecap='round'/%3E%3Cpath d='M6 6 18 18 M18 6 6 18' fill='none' stroke='%23e60000' stroke-width='2.5' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* Valid: green border; the ✅ appears once the value is user-vetted
   (:user-valid), so an untouched field and a validated one differ by more
   than colour. */
input:user-valid,
input:valid {
	border-color: var(--valid-color);
}
input:user-valid {
	--state-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24' role='img' aria-label='Valid input'%3E%3Cpath d='M5 12.6 9.8 17.6 20 5.8' fill='none' stroke='%2300AC0F' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M5 12.6 9.8 17.6 20 5.8' fill='none' stroke='%2300d112' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* Focused valid: add the glow, plus the ✅ already while typing
   (:valid turns true before :user-valid does) */
input:focus:user-valid:not(:placeholder-shown),
input:focus:valid:not(:placeholder-shown) {
	box-shadow: 0 2px 10px 0.1px color-mix(in srgb, var(--valid-color) calc(var(--shadow-strength) * 100%), transparent);
	--state-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24' role='img' aria-label='Valid input'%3E%3Cpath d='M5 12.6 9.8 17.6 20 5.8' fill='none' stroke='%2300AC0F' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M5 12.6 9.8 17.6 20 5.8' fill='none' stroke='%2300d112' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* Respect users who ask for less motion */
@media (prefers-reduced-motion: reduce) {
	input {
		transition: none;
	}
}
