/*
 * A disabled control that looks disabled.
 *
 * TABLER 1.7 DIMS A DISABLED SELECT'S TEXT, AND THE SELECT WAS THE CASE THIS WAS WRITTEN FOR.
 *
 * Through 1.6 Tabler marked a disabled select by its background alone, 1.045 against an enabled one
 * in light, so the disabled select could not be told from the enabled ones beside it, and this sheet
 * dimmed every disabled field to 0.65 for its sake. 1.7 gives .form-select:disabled the text it
 * gives .form-control:disabled, --tblr-control-disabled-color. Measured under Tabler 1.7 alone, on a
 * card in Chrome 155, the contrast of the enabled-to-disabled change:
 *
 *                      background        text
 *     light  input        1.044          2.187
 *     light  select       1.044          2.187
 *     dark   input        1.320          2.002
 *     dark   select       1.320          2.002
 *
 * Two cues each, which is what this comment called fine for the input under 1.5, and a range grays
 * its thumb. So they look as they do on Tabler's own pages, and take only the cursor below.
 *
 * A COLOR INPUT KEEPS THE OPACITY. Its content is the swatch, which Tabler leaves at full color, so a
 * disabled one differs from an enabled one by the background around the swatch alone, the 1.044
 * above. Opacity rather than another color: a color would be picked per scheme and again for a
 * control on a card rather than on the page, where opacity is a ratio, holds against any surface,
 * and dims the swatch and the border together. It is the signal Bootstrap uses for a disabled
 * button, --bs-btn-disabled-opacity, 0.65.
 *
 * not-allowed rather than Tabler's default cursor, because the pointer is the one cue that is not a
 * color, and it costs nothing. Not on a range, which Tabler gives pointer-events: none, so no cursor
 * of its own ever shows.
 *
 * This matters here beyond taste. Wicket renders `disabled` for any component with setEnabled
 * (false), and a form that disables a field until a checkbox is ticked is asking the visitor to
 * notice which is which; a settings page of inherited values is most of one.
 *
 * Checkboxes, radios and switches are deliberately absent. Tabler already dims those,
 * .form-check-input:disabled with --tblr-form-check-disabled-opacity and pointer-events: none, and
 * its label to 0.7. What is corrected on them is their unchecked edge, below.
 *
 * :disabled only. [readonly] is excluded on purpose: a readonly control is still focusable, still
 * copyable and still submitted, and dimming it would say the opposite. TablerDisabledControlsTest
 * fails when Tabler moves either half.
 */
.form-control:disabled,
.form-select:disabled {
	cursor: not-allowed;
}

.form-control-color:disabled {
	opacity: 0.65;
}

/*
 * An unchecked checkbox, radio or switch that can be seen, and a switch that can be seen to be off.
 *
 * Tabler draws a check's edge from --tblr-form-check-border, in --tblr-border-color, the gray it gives
 * every field, and fills it with --tblr-bg-forms, which in light is the card itself. So the edge is the
 * whole control, and against a card Tabler 1.7's measures 1.23 to 1.27 in light and 1.41 to 1.48 in
 * dark, where WCAG 1.4.11 asks 3:1 of a control's boundary (issue #146).
 *
 * The edge takes the gray scale's steps, gray-500 in light and gray-400 in dark, which is the pairing
 * Tabler gives --tblr-secondary. Read from the scale so it follows the theme base, and not from
 * --tblr-secondary itself, which is text and has a defect of its own (#198) whose fix should not move
 * every checkbox. Against card and page that is 4.44 or better in light and 5.71 or better in dark,
 * under every base, in Chrome 155. A field keeps Tabler's border: it is identified by its label and
 * placeholder, and a check's state is the drawing itself.
 *
 * It is set through --tblr-form-check-border, the property Tabler draws the edge from, on Tabler's own
 * selector, and wins by landing after tabler.css. Not as a border-color: every state Tabler gives an
 * edge of its own, focused, checked, indeterminate or validated, sets border-color in a heavier rule,
 * and keeps its say without a guard here. A disabled check takes this edge under Tabler's half opacity:
 * Tabler sets no edge of its own there, and its faint one at half strength hides the option rather
 * than graying it. An indeterminate radio is drawn unchecked and takes it like one.
 *
 * A switch has no edge to see. Tabler 1.7 fills an off switch with --tblr-form-switch-bg, gray-300 in
 * light and 25% white in dark, makes its border transparent, and puts a white knob on it. So the track
 * is the boundary, at 1.47 to 1.49 against a card in light and 2.26 to 2.29 in dark, and the knob on it
 * 1.47 in light. Tabler's shape stays, white knob and all; only the track moves, to halfway between
 * gray-400 and gray-500 in both schemes. That is the lightest gray that keeps the track at 3:1 against
 * card and page and the knob at 3:1 on the track, pressed too, where Tabler's brightness(90%) darkens
 * track and knob and not the card. In Chrome 155 the track measures 3.19 or better against card and
 * page in light and 4.22 in dark, 3.50 pressed, and the knob 3.19 or better on it. gray-500 would pass
 * in light and fall below 3:1 pressed on a dark card; gray-400 would leave the knob below 3:1. It is
 * declared on the input, where the track reads it, so the wrapper keeps Tabler's. An indeterminate
 * switch is drawn off and takes this track too: 1.7's off rule matches it unchecked, and Chrome 155
 * does not match :checked on an indeterminate checkbox at all, so it draws a checked one off as well.
 *
 * TablerCheckContrastTest works out the cascade on the input, its knob and its wrapper for each kind
 * of check in the states Tabler styles, follows Tabler's --tblr-form-check-* and --tblr-form-switch-*
 * properties to the colors they end at, holds the rules to the states above, and measures edge, track
 * and knob under every base, accent and scheme. These rules must stay unconditional: it refuses a rule
 * that reaches a check from inside a media query or a layer rather than guess whether it holds.
 */
.form-check-input {
	--bs5-check-edge: light-dark(var(--tblr-gray-500), var(--tblr-gray-400));
	--tblr-form-check-border: var(--tblr-border-width) var(--tblr-border-style) var(--bs5-check-edge);
}

.form-switch .form-check-input {
	--tblr-form-switch-bg: color-mix(in oklab, var(--tblr-gray-400), var(--tblr-gray-500));
}

/*
 * A checked or indeterminate checkbox, radio or switch whose mark can be read on its fill, and whose
 * fill can be told from what it sits on.
 *
 * Tabler fills a checked control with the primary and draws the tick, the dot and the switch's knob in
 * white, whatever the primary is. Under the green, lime and yellow accents that is 2.74, 2.44 and 2.13,
 * and under the inverted accent in dark, whose primary is near-white, 1.04, where WCAG 1.4.11 asks 3:1
 * of what shows a control's state (issue #159). The mark takes --tblr-primary-fg instead: Tabler's
 * variable for the text on a primary fill, the one a solid primary button reads, which
 * tabler-foreground-corrections.css re-points at black or white by the fill and the inverted accent
 * sets for itself. So a checked box carries its button's foreground, 4.62 or better under every accent,
 * and azure, cyan, orange and teal, which white passed by a hair, turn black with their buttons. Without
 * that sheet's guard it is Tabler's own near-white, as before. Reading a variable Tabler owns is not
 * reading that sheet, so deleting it the release Tabler fixes -fg leaves this right.
 *
 * The mark's rules have the selectors of the Tabler rules that paint the fill under it, and keep
 * Tabler's order, so the mark follows the fill through Tabler's own cascade: a checked, indeterminate
 * .is-valid checkbox is filled with the valid color, and gets the valid color's mark. Tabler writes
 * #fff on an indeterminate checkbox at (0,3,0), which is why that selector is here. A checked switch's
 * knob is Tabler's --tblr-form-switch-checked-color, which takes the mark, on the input so that it
 * reads the input's own mark.
 *
 * A validated fill is Tabler's valid or invalid color, which in dark is green or red mixed 40% toward
 * white, lighter than success and danger, so neither of their -fg fits. White measures 2.74 on the valid
 * fill in light, 1.77 and 2.34 on the two in dark. Those marks are the badge sheet's pick written out
 * rather than read from another sheet's property, so each sheet can be deleted alone, behind its
 * @supports condition verbatim: a custom property holding var() parses anything, and a browser without
 * relative colors would compute it invalid and leave the tick transparent. Turned away, the mark is the
 * --tblr-primary-fg of the rule before it.
 *
 * The fill is the control's boundary, and under seven light accents it is too pale for a card, yellow
 * 2.13 against one and 2.04 against the page. So a checked or indeterminate check takes an edge: the
 * primary moved 40% toward black in light and toward white in dark, the color a primary outline
 * button's label takes at rest, and the direction Tabler's own faint checked edge already leans in each
 * scheme. 6.91 or better in light and 6.07 in dark, 4.96 pressed, in Chrome 155. It is a visible line
 * round the box under every accent, the default one included, and a shade of the fill rather than a
 * gray, which would read as a second control.
 *
 * It goes through --tblr-form-check-checked-border-color and --tblr-form-check-indeterminate-border-color,
 * the properties Tabler 1.7 paints those edges from. Tabler's validated rules set border-color after its
 * checked one and tie or outrank it, so a validated edge survives with no guard here, and so does a
 * .was-validated form's edge on an indeterminate checkbox, which 1.6 needed two restated rules for.
 *
 * TablerCheckContrastTest holds the mark to its fill and the edge to the card and the page, under every
 * base, accent and scheme, pressed or not, and holds each rule to the states above.
 */
.form-check-input:checked,
.form-check-input[type=checkbox]:indeterminate {
	--tblr-form-check-icon-color: var(--tblr-primary-fg);
}

.form-switch .form-check-input {
	--tblr-form-switch-checked-color: var(--tblr-form-check-icon-color);
}

.form-check-input {
	--bs5-check-fill-edge: light-dark(color-mix(in oklab, var(--tblr-black) 40%, var(--tblr-primary)),
		color-mix(in oklab, var(--tblr-white) 40%, var(--tblr-primary)));
	--tblr-form-check-checked-border-color: var(--bs5-check-fill-edge);
	--tblr-form-check-indeterminate-border-color: var(--bs5-check-fill-edge);
}

@supports (color: oklch(from light-dark(red, blue) clamp(0, (1 - l) * 1000, 1) 0 0)) {
	.was-validated .form-check-input:valid:checked,
	.form-check-input.is-valid:checked {
		--tblr-form-check-icon-color: oklch(from var(--tblr-form-valid-color) clamp(0, (0.62 - l) * 1000, 1) 0 0);
	}

	.was-validated .form-check-input:invalid:checked,
	.form-check-input.is-invalid:checked {
		--tblr-form-check-icon-color: oklch(from var(--tblr-form-invalid-color) clamp(0, (0.62 - l) * 1000, 1) 0 0);
	}
}

/*
 * The small size on a phone, where Tabler changes the text and not the line.
 *
 * Below 576px Tabler sets .form-control and .form-select to 16px text, so iOS does not zoom the page
 * when one takes focus:
 *
 *     @media (max-width: 575.98px) {
 *       .form-control, .form-select { font-size: var(--tblr-form-control-mobile-font-size) }
 *     }
 *
 * It leaves the small size's 1rem line under that 16px text, and Chrome will not set an input's line
 * below the font's normal one, so some small controls rise and the rest do not. Measured at 375px in
 * Chrome 155 with Inter, against Tabler 1.7.0 without this block (sizes.mjs beside the tests, with
 * --without tabler-form-corrections.css):
 *
 *     text and date inputs, alone or in a group    36
 *     every other small control                    32   a select, a button, a file input, a
 *                                                       textarea, a color input, a searchable select
 *
 * So every small control takes the default size's line here, --tblr-btn-input-line-height, the one
 * Tabler itself puts under this same 16px text at the default size, and all of them stand 36px in
 * every engine rather than in the ones that raise an input's line. Each takes it through the property
 * Tabler sizes it by: --tblr-control-line-height on a sized field, --tblr-input-group-addon-line-height
 * on a small group, which the group's field and addon both read, and --tblr-btn-line-height on a
 * button. A button inside a small group is the one Tabler gives a literal line-height, so it gets one
 * back. A small color input's height and a searchable select's box are built from the same properties
 * and follow without rules of their own.
 *
 * 36 rather than 32, because 32 would need the 1rem line an input will not keep or less of Tabler's
 * padding, and 36 is a larger target where touch is the input.
 *
 * Buttons take the height and keep their 12px text. iOS does not zoom on a button, and Tabler's phone
 * rule leaves a default one at 14px beside 16px fields, so 16px on a small button would read larger
 * than a default one. The addon in a small group keeps its 12px for the same reason.
 *
 * Tabler 1.6 needed a fourth rule here: its small group set its field's text at two classes, which
 * outranked the one-class phone rule, so a field with an addon stayed at 12px and zoomed. 1.7's group
 * rule sets only properties, and the phone rule reaches the field, measured at 16px.
 *
 * Tabler's breakpoint exactly, so no width falls between the two. Each selector is the one Tabler
 * declares the property on, so specificities match and source order decides, which is why the
 * reference declares tabler.css as its dependency. TablerSizedControlsTest reads the breakpoint and the
 * phone text from tabler.css and checks that every small control still sums to one height here;
 * sizes.mjs measures the boxes.
 */
@media (max-width: 575.98px) {
	.form-control-sm,
	.form-select-sm {
		--tblr-control-line-height: var(--tblr-btn-input-line-height);
	}

	.input-group-sm {
		--tblr-input-group-addon-line-height: var(--tblr-btn-input-line-height);
	}

	.input-group-sm > .btn {
		line-height: var(--tblr-btn-input-line-height);
	}

	.btn-sm,
	.btn-group-sm > .btn {
		--tblr-btn-line-height: var(--tblr-btn-input-line-height);
	}
}

/*
 * A password reveal that sits inside the field rather than beside it.
 *
 * PasswordFormField.revealable() renders its toggle in the input group's own .input-group-text
 * span, which is the right structure and, under both Bootstrap and Tabler, the wrong appearance for
 * this particular addon: the span carries its own border and background, so a control that belongs
 * to the field reads as a second segment bolted onto it, divided by a rule.
 *
 * Tabler ships the answer as .input-group-flat, and it cannot be used from where the markup is
 * written - that class has to sit on the group element, and the group is wicket-bootstrap5's, a
 * theme-free module that cannot name a Tabler class. So the treatment is applied here, selected by
 * the marker the library does write. :has() for the same reason: it lets the theme key off markup
 * the other module owns, and needs no new plumbing in FormField to expose the group. Baseline
 * across browsers since 2023.
 *
 * EVERY VALUE AN APPLICATION MIGHT DISAGREE WITH IS A CUSTOM PROPERTY WITH A FALLBACK, AND THAT IS
 * NOT DECORATION.
 *
 * The first version of this sheet wrote the focus ring and the focus border directly. Both are
 * (0,3,0), the same as an application's own `.some-card .input-group:focus-within`, so the two tied
 * and source order decided - and this sheet is contributed by the theme, after the application's.
 * A sign-in page styled entirely in its own accent therefore got Tabler's primary blue on one field
 * out of five, and the only way out was to escalate specificity with a `:has(.bs5-reveal)` selector
 * of its own. Measured on exactly that page before this was rewritten.
 *
 * Declared as fallbacks at the point of use rather than set on the group, which matters: a property
 * set on .input-group would beat one an application inherits from an ancestor, and the ancestor is
 * where an application naturally states its palette. `var(--x, default)` loses to any declaration
 * anywhere above it, which is the behaviour wanted.
 *
 * The ring itself has no property of ours, because since Tabler 1.6 it has one of Tabler's. The
 * group draws .input-group-flat:focus-within exactly - an outline of --tblr-focus-ring-width in
 * --tblr-focus-ring-color, inset a pixel, rounded as the group's addons are - and Tabler declares
 * that color on :root only, so an application setting it on an ancestor re-tints this ring and every
 * native control's beside it in one declaration. The --bs5-reveal-ring this replaced took a
 * box-shadow, which was Tabler 1.5's shape; kept, it would have drawn a halo next to controls that
 * now draw an outline.
 *
 * WHY NOT .input-group-flat'S OWN RULES, NOW THAT THEY ARE THE MODEL FOR EVERY ONE BELOW. They key on
 * the addon being the group's last child, and FormField puts the invalid feedback last, inside the
 * group, as Bootstrap's has-validation markup does. So flat's seam rule misses the addon exactly when
 * the field is invalid, and the seam comes back at 4.66 against the card. Selected by the reveal
 * marker instead, everything here holds with the feedback present. Measured in Chrome 155 against
 * Tabler 1.7 alone: the addon differs from the input at 1.03 in light and 1.30 in dark, the seam at
 * 1.26 and 1.73, and with this block at 1.00 in every state. states.mjs holds it.
 */
.input-group:has(.bs5-reveal) > .form-control:not(:last-child) {
	border-inline-end: 0;
}

/*
 * The addon holding the toggle, not every addon in the group.
 *
 * `.input-group:has(.bs5-reveal) > .input-group-text` was the first spelling and it matched both:
 * a password field with a leading lock glyph lost that glyph's left border too, so the field opened
 * at its left edge instead of closing the seam at its right. Selecting the addon that contains the
 * control keeps it to the one that needs it, and drops the group-level :has() as redundant.
 *
 * Painted through the property Tabler paints an addon with, at flat's value, the field's own fill, so
 * an application's rule on the addon still wins as it would on any addon. And above the group's ring,
 * as flat's is: a focused input is raised above it already, and an addon left below had the ring
 * cover its border while the input's showed, two edges on one field.
 */
.input-group > .input-group-text:has(.bs5-reveal) {
	z-index: 10;
	border-inline-start: 0;
	--tblr-input-group-addon-bg: var(--bs5-reveal-addon-bg, var(--tblr-btn-input-bg));
}

/*
 * Disabled, the addon takes the disabled field's fill. Since Tabler 1.7 that is a translucent tint of
 * the body color in dark, which an opaque addon beside it showed as a second shade, 1.30 against the
 * input. And the group overlaps the addon a pixel onto the input to merge their borders, which with a
 * translucent fill on both is a column tinted twice, a faint seam at 1.11; the addon's start border,
 * transparent and outside its clipped fill, keeps that column to the input's tint alone.
 */
.input-group:has(.bs5-reveal):has(> .form-control:disabled) > .input-group-text {
	--tblr-input-group-addon-bg: var(--tblr-bg-forms-disabled);
	border-inline-start: var(--tblr-border-width) solid transparent;
	background-clip: padding-box;
}

.input-group:has(.bs5-reveal):focus-within {
	--tblr-focus-ring-offset: -1px;
	border-radius: var(--tblr-input-group-addon-border-radius);
	outline: var(--tblr-focus-ring, var(--tblr-focus-ring-width) solid var(--tblr-focus-ring-color));
	outline-offset: var(--tblr-focus-ring-offset);
}

/*
 * Both halves take the focus border, flat's tint of the primary, or the ring frames two
 * differently-edged pieces.
 */
.input-group:has(.bs5-reveal):focus-within > .form-control,
.input-group:has(.bs5-reveal):focus-within > .input-group-text {
	border-color: var(--bs5-reveal-focus-border, color-mix(in oklab, var(--tblr-white) 50%, var(--tblr-primary)));
}

/*
 * A validated field, as flat draws one: the addon's border in the validation color at rest, and on
 * focus the ring in the validation mix and both halves' border in the validation color. The ring's
 * color is set as a longhand, as flat's is, so it overrides the color of an application's own
 * --tblr-focus-ring as validation does on a native control, and the border with !important, as flat's
 * is, so it overrides --bs5-reveal-focus-border too. Before this the focus rule above outranked
 * Tabler's .form-control.is-invalid:focus, and an invalid field took the primary ring and a gray edge.
 */
.input-group:has(.bs5-reveal):has(> .form-control.is-valid) > .input-group-text,
.was-validated .input-group:has(.bs5-reveal):has(> .form-control:valid) > .input-group-text {
	border-color: var(--tblr-form-valid-border-color);
}

.input-group:has(.bs5-reveal):has(> .form-control.is-valid):focus-within,
.was-validated .input-group:has(.bs5-reveal):has(> .form-control:valid):focus-within {
	outline-color: light-dark(color-mix(in oklab, var(--tblr-success) calc(var(--tblr-focus-ring-opacity) * 100%), var(--tblr-body-bg)), color-mix(in oklab, var(--tblr-success) calc(var(--tblr-focus-ring-opacity-dark) * 100%), var(--tblr-body-bg)));
}

.input-group:has(.bs5-reveal):has(> .form-control.is-valid):focus-within > .form-control,
.input-group:has(.bs5-reveal):has(> .form-control.is-valid):focus-within > .input-group-text,
.was-validated .input-group:has(.bs5-reveal):has(> .form-control:valid):focus-within > .form-control,
.was-validated .input-group:has(.bs5-reveal):has(> .form-control:valid):focus-within > .input-group-text {
	border-color: var(--tblr-form-valid-border-color) !important;
}

.input-group:has(.bs5-reveal):has(> .form-control.is-invalid) > .input-group-text,
.was-validated .input-group:has(.bs5-reveal):has(> .form-control:invalid) > .input-group-text {
	border-color: var(--tblr-form-invalid-border-color);
}

.input-group:has(.bs5-reveal):has(> .form-control.is-invalid):focus-within,
.was-validated .input-group:has(.bs5-reveal):has(> .form-control:invalid):focus-within {
	outline-color: light-dark(color-mix(in oklab, var(--tblr-danger) calc(var(--tblr-focus-ring-opacity) * 100%), var(--tblr-body-bg)), color-mix(in oklab, var(--tblr-danger) calc(var(--tblr-focus-ring-opacity-dark) * 100%), var(--tblr-body-bg)));
}

.input-group:has(.bs5-reveal):has(> .form-control.is-invalid):focus-within > .form-control,
.input-group:has(.bs5-reveal):has(> .form-control.is-invalid):focus-within > .input-group-text,
.was-validated .input-group:has(.bs5-reveal):has(> .form-control:invalid):focus-within > .form-control,
.was-validated .input-group:has(.bs5-reveal):has(> .form-control:invalid):focus-within > .input-group-text {
	border-color: var(--tblr-form-invalid-border-color) !important;
}

/*
 * The control's own ring would otherwise be drawn inside the group's, one rectangle within another.
 * Both properties, because Tabler 1.6 moved that ring from box-shadow to outline: clearing only the
 * shadow, as this did through 1.5, let the input's outline back in beside the group's.
 */
.input-group:has(.bs5-reveal) > .form-control:focus {
	outline: 0;
	box-shadow: none;
}

/*
 * An addon that moves with the control it belongs to.
 *
 * Tabler gives .form-control `transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out`
 * and gives .input-group-text nothing - measured at `all` with a duration of 0s. So on focus the
 * control eases over 150ms while the chip beside it changes instantly, and a field that is drawn as
 * one box visibly comes apart for the length of the transition and puts itself back together.
 *
 * Not specific to the password reveal, which is where this was first noticed and first fixed. It is
 * every input group with an addon: a leading icon on an e-mail field shows it just as plainly.
 * Tabler declares the same transition itself, but only under .input-group-flat, so the fix here is
 * to stop that being the one arrangement that behaves.
 *
 * background-color is included because a theme that tints the addon on focus - which this one does
 * in its sign-in card - otherwise animates the border and jumps the fill.
 *
 * Deliberately (0,1,0). This is a default an application should be able to overrule with any rule
 * of its own, which is the mistake the reveal block above was rewritten to stop making.
 */
.input-group-text {
	transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out,
		background-color .15s ease-in-out;
}

@media (prefers-reduced-motion: reduce) {
	.input-group-text {
		transition: none;
	}
}

/*
 * A phone field's country search box, focused, draws Tabler's field ring rather than the Bootstrap
 * halo wicket-bootstrap5's tel-input-corrections.css gives it: under Tabler that was a 4px band of the
 * ring color beside fields drawing a 2px outline. Inset by the ring's own width, through the
 * --tblr-focus-ring-offset Tabler's outline reads, as the close button's is: the box spans its panel,
 * so a ring at Tabler's 2px outward offset would stand outside the panel's edges.
 *
 * :root for specificity, since that sheet arrives with the field and this with the theme, and either
 * may land first. TablerFocusRingTripwireTest holds the ring to Tabler's, and states.mjs measures it
 * on the open widget beside a focused field, under both templates.
 */
:root .iti:has(> [data-bs5-tel]) .iti__search-input:focus,
:root .bs5-tel-popup .iti__search-input:focus {
	--tblr-focus-ring-offset: calc(-1 * var(--tblr-focus-ring-width));
	outline: var(--tblr-focus-ring, var(--tblr-focus-ring-width) solid var(--tblr-focus-ring-color));
	outline-offset: var(--tblr-focus-ring-offset);
	box-shadow: none;
}
