/*
 * Form controls.
 *
 * Two things about the edge are worth knowing before changing anything here.
 *
 * Figma draws strokes *inside* the frame, which is why every variant in the
 * file is 40px tall whether its border is 1px or the focused 2px. A CSS border
 * grows the box instead, so the edge is an inset box-shadow: it lands in the
 * same place, and going 1px to 2px on focus moves nothing. Everything that
 * needs to match that edge — the divider beside a leading add-on — reads the
 * same --lp-edge custom property, so a state only has to be set in one place.
 *
 * State is taken from the control itself rather than from classes the caller
 * has to keep in sync: :placeholder-shown is the empty state, :focus-within is
 * focus, :disabled is disabled. Only the error state is a modifier, because
 * nothing in the DOM knows whether a value was rejected.
 */

/* Field ------------------------------------------------------------------ */

.lp-field {
	display: flex;
	flex-direction: column;
	gap: var(--lp-field-gap);
	font-family: var(--lp-font);
}

.lp-field__label {
	display: flex;
	gap: var(--lp-space-xxs);
	font-size: var(--lp-text-sm);
	font-weight: var(--lp-weight-medium);
	line-height: var(--lp-text-sm-line);
	color: var(--lp-ink-label);
}

.lp-field__required {
	color: var(--lp-ink-required);
}

.lp-field__hint {
	margin: 0;
	font-size: var(--lp-text-sm);
	font-weight: var(--lp-weight-regular);
	line-height: var(--lp-text-sm-line);
	color: var(--lp-ink-hint);
}

.lp-field--error .lp-field__required,
.lp-field--error .lp-field__hint {
	color: var(--lp-danger-ink);
}

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

.lp-control {
	--lp-edge: var(--lp-edge-filled);
	--lp-edge-size: var(--lp-edge-width);

	display: flex;
	align-items: center;
	gap: var(--lp-control-gap);
	min-height: var(--lp-control-height);
	padding: var(--lp-control-pad-y) var(--lp-control-pad-x);
	background: var(--lp-surface);
	box-shadow: inset 0 0 0 var(--lp-edge-size) var(--lp-edge);
}

/*
 * An empty control is a shade greyer than a filled one. Text fields and
 * selects say so themselves; a date input cannot — it has no placeholder to
 * be showing and its value attribute does not track what the user typed — so
 * for those the caller adds .lp-control--empty, or leaves the field looking
 * filled, which is the smaller of the two errors.
 *
 * The :has() arguments are wrapped in :where() so they weigh nothing: :has()
 * otherwise takes the specificity of its argument, and this rule would then
 * outrank the error and focus states that are supposed to override it.
 */
.lp-control:has(:where(.lp-control__input:placeholder-shown, .lp-control__textarea:placeholder-shown)),
.lp-control:has(:where(.lp-control__select option[value=""]:checked)),
.lp-control--empty {
	--lp-edge: var(--lp-edge-empty);
	background: var(--lp-surface-empty);
}

.lp-control:focus-within {
	--lp-edge: var(--lp-accent);
	--lp-edge-size: var(--lp-edge-width-focus);
	background: var(--lp-surface);
}

.lp-field--error .lp-control {
	--lp-edge: var(--lp-danger-subtle);
	background: var(--lp-surface);
}

.lp-field--error .lp-control:focus-within {
	--lp-edge: var(--lp-danger);
	--lp-edge-size: var(--lp-edge-width-focus);
}

/* Disabled is drawn at full strength and then faded, exactly as in Figma —
   fading the parts individually gives a different, muddier result. */
.lp-control:has(:disabled) {
	--lp-edge: var(--lp-edge-disabled);
	background: var(--lp-surface);
	opacity: var(--lp-disabled-opacity);
}

/* The field itself: no chrome of its own, the wrapper draws all of it. */
.lp-control__input {
	flex: 1 0 0;
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	font-family: inherit;
	font-size: var(--lp-text-md);
	font-weight: var(--lp-weight-regular);
	line-height: var(--lp-text-md-line);
	color: var(--lp-ink);
	text-overflow: ellipsis;
}

.lp-control__input:focus {
	outline: none;
}

.lp-control__input::placeholder {
	color: var(--lp-ink-placeholder);
	opacity: 1;
}

.lp-control__input:disabled {
	cursor: not-allowed;
	-webkit-text-fill-color: var(--lp-ink);
}

/* Checkbox ----------------------------------------------------------------
 *
 * A standalone checkbox with a label beside it — the "Other" toggle under a
 * choice field. The box is drawn rather than native, because a native one
 * cannot take the brand fill; the tick is the same icon the menu rows use.
 */
.lp-checkbox {
	display: flex;
	align-items: flex-start;
	gap: var(--lp-space-md);
	font-family: var(--lp-font);
}

.lp-checkbox__input {
	flex: none;
	appearance: none;
	-webkit-appearance: none;
	width: var(--lp-box-sm);
	height: var(--lp-box-sm);
	/* Sits on the label's cap height rather than its line box. */
	margin: var(--lp-space-xxs) 0 0;
	border: var(--lp-edge-width) solid var(--lp-edge-checkbox);
	background: var(--lp-surface);
	cursor: pointer;
}

.lp-checkbox__input:checked {
	border-color: var(--lp-accent);
	background: var(--lp-accent) url("icons/check.svg") no-repeat center / 9.6667px 7.1667px;
}

.lp-checkbox__input:focus-visible {
	outline: var(--lp-edge-width-focus) solid var(--lp-accent-ring);
	outline-offset: 1px;
}

/*
 * Scoped to .lp-checkbox to outweigh chaplin's `input[type="checkbox"] + label`.
 * That selector is (0,1,2) and beats a lone class, forcing weight 400 and a .5rem
 * margin that lands on top of the row's own 8px gap -- 13px where the design says 8.
 */
.lp-checkbox .lp-checkbox__label {
	font-size: var(--lp-text-sm);
	font-weight: var(--lp-weight-medium);
	line-height: var(--lp-text-sm-line);
	letter-spacing: 0.14px;
	color: var(--lp-ink-option);
	margin-inline-start: 0;
	cursor: pointer;
}

/* Adornments ------------------------------------------------------------- */

/*
 * The icons are the Figma exports unaltered, cropped to their own paths and
 * carrying the colour the design gives them. Each sits centred in a box of
 * the size the design reserves for it, which is what the crop assumes.
 */
.lp-control__icon,
.lp-control__help,
.lp-control__alert,
.lp-control__chevron {
	display: flex;
	align-items: center;
	justify-content: center;
}

.lp-control__icon img,
.lp-control__help img,
.lp-control__alert img,
.lp-control__chevron img {
	display: block;
}

.lp-control__icon {
	flex: none;
	width: var(--lp-icon-md);
	height: var(--lp-icon-md);
}

.lp-control__help {
	position: relative;
	flex: none;
	width: var(--lp-icon-sm);
	height: var(--lp-icon-sm);
	padding: 0;
	border: 0;
	background: none;
	cursor: pointer;
}

/* Help popovers are plain HTML/CSS; the preview's small script only keeps
   them open after a touch/click. The same markup also works on hover and
   keyboard focus without JavaScript. */
.lp-control__tooltip {
	position: absolute;
	top: calc(100% + var(--lp-space-md));
	right: 0;
	z-index: 2;
	width: max-content;
	max-width: 240px;
	padding: var(--lp-space-md) var(--lp-space-lg);
	border-radius: 8px;
	background: #0a0a0a;
	box-shadow: 0 12px 8px rgba(0, 0, 0, 0.08), 0 4px 3px rgba(0, 0, 0, 0.03), 0 2px 1px rgba(0, 0, 0, 0.04);
	color: #fff;
	font-family: var(--lp-font);
	font-size: 12px;
	font-weight: var(--lp-weight-medium);
	line-height: 18px;
	text-align: center;
	visibility: hidden;
	opacity: 0;
	transform: translateY(-2px);
	transition: opacity 120ms ease, transform 120ms ease, visibility 120ms;
}

.lp-control__help:hover .lp-control__tooltip,
.lp-control__help:focus .lp-control__tooltip,
.lp-control__help.is-open .lp-control__tooltip {
	visibility: visible;
	opacity: 1;
	transform: translateY(0);
}

/* The alert and the help button share the trailing slot and the error wins it.
   Both are always in the markup so view.js can put a field into error by
   setting one class, with no icon URL of its own to keep in step with the PHP. */
.lp-control__alert {
	display: none;
	flex: none;
	width: var(--lp-icon-sm);
	height: var(--lp-icon-sm);
}

.lp-field--error .lp-control__alert {
	display: flex;
}

.lp-field--error .lp-control__help {
	display: none;
}

/*
 * A leading add-on — the "https://" on a URL, the country code on a phone —
 * sits outside the control's own padding and is divided from the field by a
 * line matching the current edge.
 *
 * The control gives up its vertical padding as well as its left, and the two
 * halves carry their own instead. Figma draws the divider as the text half's
 * own border, so it runs the full height of the field; left inside the
 * control's padding it stopped 8px short at the top and bottom. The right
 * padding stays, because the trailing help or alert icon still sits in it.
 */
.lp-control:has(.lp-control__addon) {
	padding: 0 var(--lp-control-pad-x) 0 0;
	gap: 0;
}

/* The text half's own inset, in place of the padding and gap given up above. */
.lp-control:has(.lp-control__addon) .lp-control__input {
	padding: var(--lp-control-pad-y) var(--lp-control-pad-x);
}

.lp-control__addon {
	flex: none;
	display: flex;
	align-items: center;
	align-self: stretch;
	gap: var(--lp-space-xxs);
	padding: 0 var(--lp-control-pad-x);
	border-right: var(--lp-edge-width) solid var(--lp-edge);
	font-size: var(--lp-text-md);
	font-weight: var(--lp-weight-regular);
	line-height: var(--lp-text-md-line);
	color: var(--lp-ink-hint);
	white-space: nowrap;
}

/* The country-code select inside an add-on: text and a chevron, no box. */
.lp-control__addon select {
	appearance: none;
	-webkit-appearance: none;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	font: inherit;
	color: inherit;
	cursor: pointer;
}

.lp-control__addon select:focus {
	outline: none;
}

/*
 * A trailing dropdown is its own hit area at the end of the control, so it
 * carries the horizontal padding rather than the control doing it.
 */
.lp-control:has(.lp-control__chevron) {
	padding-right: 0;
}

.lp-control__chevron {
	flex: none;
	align-self: stretch;
	width: calc(var(--lp-control-pad-x) * 2 + var(--lp-icon-sm));
	pointer-events: none;
}

/* Select ----------------------------------------------------------------- */

.lp-control__select {
	appearance: none;
	flex: 1 0 0;
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	font-family: inherit;
	font-size: var(--lp-text-md);
	font-weight: var(--lp-weight-regular);
	line-height: var(--lp-text-md-line);
	color: var(--lp-ink);
	cursor: pointer;
}

.lp-control__select:focus {
	outline: none;
}

/* Nothing chosen yet reads as a placeholder. */
.lp-control__select:has(option[value=""]:checked) {
	color: var(--lp-ink-placeholder);
}

.lp-control__select:disabled {
	cursor: not-allowed;
}

/* Date ------------------------------------------------------------------- */

/*
 * Date fields deliberately use text input rather than the browser's native
 * date widget. Native controls localise their placeholder and value (for
 * example Chrome renders mm/dd/yyyy), whereas the component specifies the
 * stable DD / MM / GGGG format shown in the design.
 */

/* Textarea --------------------------------------------------------------- */

.lp-control--textarea {
	position: relative;
	box-sizing: border-box;
	align-items: stretch;
	height: var(--lp-textarea-height);
	padding: var(--lp-textarea-pad-y) var(--lp-textarea-pad-x);
	overflow: hidden;
	resize: vertical;
}

.lp-control__textarea {
	flex: 1 0 0;
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	font-family: inherit;
	font-size: var(--lp-text-md);
	font-weight: var(--lp-weight-regular);
	line-height: var(--lp-text-md-line);
	color: var(--lp-ink);
	resize: none;
}

.lp-control__textarea:focus {
	outline: none;
}

.lp-control__textarea::placeholder {
	color: var(--lp-ink-placeholder);
	opacity: 1;
}

/* Choice: checkbox and radio --------------------------------------------- */

.lp-choice {
	display: flex;
	gap: var(--lp-space-lg);
	font-family: var(--lp-font);
}

.lp-choice__input {
	appearance: none;
	box-sizing: border-box;
	flex: none;
	width: var(--lp-box-md);
	height: var(--lp-box-md);
	/* The box sits on the cap height of a 24px line, not on its top edge. */
	margin: var(--lp-space-xxs) 0 0;
	border: var(--lp-edge-width) solid var(--lp-edge-disabled);
	background: var(--lp-surface);
	cursor: pointer;
}

.lp-choice__input[type="radio"] {
	border-radius: 50%;
}

/* Once it is filled there is no outline left, only the block of colour — so
   the border goes rather than turning green, which would darken the edge. */
.lp-choice__input:checked,
.lp-choice__input:indeterminate {
	border: 0;
	background-color: var(--lp-accent);
}

/* The glyphs are the exported Figma vectors, masked so CSS owns the colour.
   Each mask is sized to the vector's own dimensions rather than stretched,
   because the exports are cropped to the path and carry no padding. */
.lp-choice__input:checked::after,
.lp-choice__input:indeterminate::after {
	content: "";
	display: block;
	width: 100%;
	height: 100%;
	background: #ffffff;
}

.lp-choice__input[type="checkbox"]:checked::after {
	content: none;
	background: none;
}

.lp-choice__input[type="checkbox"]:indeterminate::after {
	content: none;
	background: none;
}

/* Inputs with appearance:none do not paint pseudo-elements consistently in
   every browser. Use Figma's exported glyphs as the checkbox background. */
.lp-choice__input[type="checkbox"]:checked {
	background-image: url("icons/check.svg");
	background-position: center;
	background-repeat: no-repeat;
	background-size: 11.3333px 8.4167px;
}

.lp-choice__input[type="checkbox"]:indeterminate {
	background-image: url("icons/minus.svg");
	background-position: center;
	background-repeat: no-repeat;
	background-size: 10.1667px 2px;
}

/* The radio's dot is inset 30%, which is the same as a full-bleed circle
   scaled to 40% — and that way it stays centred at either size. */
.lp-choice__input[type="radio"]:checked::after {
	border-radius: 50%;
	transform: scale(0.4);
}

.lp-choice__input:focus-visible {
	outline: none;
	box-shadow:
		0 0 0 2px var(--lp-surface),
		0 0 0 4px var(--lp-accent-ring);
}

.lp-choice__input:disabled {
	border-color: var(--lp-edge-disabled);
	background-color: var(--lp-surface-disabled);
	opacity: var(--lp-disabled-opacity);
	cursor: not-allowed;
}

.lp-choice__input:disabled:checked,
.lp-choice__input:disabled:indeterminate {
	background-color: var(--lp-accent);
}

.lp-choice__text {
	display: flex;
	flex: 1 0 0;
	min-width: 0;
	flex-direction: column;
	gap: var(--lp-space-xxs);
}

.lp-choice__label {
	font-size: var(--lp-text-md);
	font-weight: var(--lp-weight-medium);
	line-height: var(--lp-text-md-line);
	color: var(--lp-ink-option);
	cursor: pointer;
}

.lp-choice__support {
	margin: 0;
	font-size: var(--lp-text-md);
	font-weight: var(--lp-weight-regular);
	line-height: var(--lp-text-md-line);
	color: var(--lp-ink-option-support);
}

.lp-choice:has(:disabled) .lp-choice__label,
.lp-choice:has(:disabled) .lp-choice__support {
	opacity: var(--lp-disabled-opacity);
	cursor: not-allowed;
}

/* The small size is not the medium one scaled: it drops to 14px text, closes
   the gap between the two lines, and tightens the label's tracking. */
.lp-choice--sm {
	gap: var(--lp-control-gap);
}

.lp-choice--sm .lp-choice__input {
	width: var(--lp-box-sm);
	height: var(--lp-box-sm);
}

.lp-choice--sm .lp-choice__input[type="checkbox"]:checked::after {
	background-size: 9.0667px 6.7333px;
}

.lp-choice--sm .lp-choice__input[type="checkbox"]:indeterminate::after {
	background-size: 8.1333px 1.6px;
}

.lp-choice--sm .lp-choice__input[type="checkbox"]:checked {
	background-size: 9.0667px 6.7333px;
}

.lp-choice--sm .lp-choice__input[type="checkbox"]:indeterminate {
	background-size: 8.1333px 1.6px;
}

.lp-choice--sm .lp-choice__text {
	gap: 0;
}

.lp-choice--sm .lp-choice__label,
.lp-choice--sm .lp-choice__support {
	font-size: var(--lp-text-sm);
	line-height: var(--lp-text-sm-line);
}

.lp-choice--sm .lp-choice__label {
	letter-spacing: 0.14px;
}
