/* =============================================================================
 * Frihat Legal Platform â€” Design System
 * 05-forms.css : every input surface (slice A4, part 1 of 2)
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * Stack   : .NET 10 / ABP 10.5.0, LeptonXLite 5.4.0 on Bootstrap 5.3,
 *           Razor Pages + jQuery validation unobtrusive, Arabic first (RTL).
 * Themes  : light by default, dark via html[data-bs-theme="dark"].
 * Tokens  : consumes 00-tokens.css only. No literal colour is written here.
 *
 * DESIGN CONTRACT
 *   Bare elements are styled alongside the Bootstrap classes, so a brand new
 *   Razor page (or a jQuery built dialog such as the Courts / Cases modals,
 *   which emit un classed <input>, <select> and <textarea>) already inherits
 *   the platform look with zero extra markup.
 *
 * RTL
 *   Logical properties only. The five deliberate physical exceptions are
 *   flagged inline: the switch knob travel, the numeric value direction, the
 *   validation summary band offset, the date editor's alignment inside Blink's
 *   shadow tree (section 10.2a), and the typed date field's alignment (section
 *   10.1b). The last two share one cause: both rules are already gated on
 *   `:dir(rtl)`, so `right` IS the inline end, while a logical `end` would
 *   resolve against the control's own forced LTR direction and point the wrong
 *   way. Everything else mirrors automatically.
 *
 * ACCESSIBILITY (WCAG 2.2 AA)
 *   Text 4.5:1, borders and UI 3:1, focus ring 3:1 against both the control and
 *   the page. Focus is expressed with :focus-visible only, so pointer users are
 *   not shown a ring. Error state is never colour alone: it always carries a
 *   glyph and text.
 *
 *   SC 2.5.8 target size survives the compact type scale. The control heights
 *   come from the tokens, and the small controls of a form are the risk:
 *   checkboxes, radios, switch knobs, the file trigger and the reveal toggle.
 *   Each of those is built as a 24px BOX whose visible artwork is 16px, using a
 *   transparent border plus background-clip padding-box. The element stays a
 *   24px hit target while reading as the 16px Linear control beside 15px text.
 *   A coarse pointer bumps every control through the token tier by itself.
 *
 * FLUIDITY
 *   No layout box carries a fixed pixel width. Fields are 100 percent of a
 *   fluid wrapper, the form grid is auto-fit with a min() guard so a 390px
 *   phone cannot overflow, and an ultrawide cap stops a text field spanning
 *   1200px on a 4K monitor. Viewport units, where used, are dvh or svh.
 *
 * COMPLIANCE
 *   This platform holds ProfessionalSecret legal data (Advocates Law 3/1999
 *   art. 28). Section 15 provides the masking presentation hooks. Read the
 *   warning there: CSS masking is presentation, never a security control.
 *   Nothing in this file requires an inline style or an inline event handler,
 *   so a future Content Security Policy stays achievable.
 *
 * â•â•â• THE LINEAR FIELD SYSTEM â€” RETUNED 2026-08-02 â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 *   THE WELL IS THE IDENTITY. Linear strips input chrome and puts the whole of
 *   a field's identity on its WELL: a filled background one plane above the
 *   surface behind it, plus the inset fx-shadow-well, and no heavy border. Not
 *   one control in this file carries a PAINTED border in its resting state.
 *   Every `border` declaration below is one of exactly four things and never a
 *   resting line: `border: 0`, which NEUTRALISES the hairline that Bootstrap,
 *   LeptonX and the user agent stylesheet each supply and is the only reason a
 *   control renders unstroked at all; a fully TRANSPARENT border, which paints
 *   nothing and exists solely to buy hit area on a replaced element; the
 *   VALIDATION border of section 14, which is a state and not a resting style;
 *   or one of the three sanctioned stroke-return contexts named below. Deleting
 *   a `border: 0` does not remove a border â€” it hands the control back to
 *   Bootstrap's 1px hairline, which is the exact defect the client rejected.
 *
 *   GEOMETRY. A text control is fx-control-h-lg (40px) tall with fx-radius-md
 *   (8px) corners. 40px, not 32px: 32px is a MENU ITEM height in this system â€”
 *   the thing you click â€” and 40px is the thing you type into. A chip or badge
 *   is fx-radius-sm, a panel-shaped surface (the drop zone, the choice card) is
 *   fx-radius-lg. Nothing in a form is a pill except the two shapes that
 *   genuinely are one: the switch track and the range rail. fx-radius-control
 *   belongs to buttons and is deliberately never read here.
 *
 *   THE MEASURED WELL, un-blurred peak against the resting fill:
 *       LIGHT  inset 0 2px 4px rgba(15,42,24,.60) over #f7fbf5
 *              â†’ rgb(108,126,112)   4.13:1   PASS
 *       DARK   inset 0 1px 3px rgba(231,239,230,.50) over #1b291f
 *              â†’ rgb(129,140,130)   4.34:1   PASS
 *   Note the direction flip: in dark the band is a RIM LIGHT along the top
 *   interior, because pure black against the dark fill reaches only 1.39:1 and
 *   no darker band could ever clear 3:1. That pairing â€” fill difference AND
 *   depth â€” is what keeps an unstroked control identifiable under WCAG 2.2
 *   SC 1.4.11, so a component must never flatten the well, lighten those alphas
 *   or substitute a weaker inset of its own to "clean it up": doing so is an
 *   accessibility regression, not a style preference. Strokes come back in
 *   exactly three places, all deliberate: prefers-contrast: more,
 *   forced-colors: active, and print. Each is commented where it appears.
 *
 *   FOCUS IS AN OUTLINE. Not a bloom, not a glow, not a lift. The control
 *   brightens its well to fx-color-field-bg-focus, and 01-base's single
 *   `:focus-visible { outline: 2px solid fx-color-focus-ring; outline-offset:
 *   2px }` draws the indicator. The overlay pseudo-element that used to carry a
 *   scaling halo is GONE â€” see section 2.1 for what replaced it and why.
 *   fx-shadow-focus-glow is deprecated and is not referenced anywhere below.
 *
 *   VALIDATION DOES NOT FILL THE FIELD. Linear has no red-tinted input
 *   background and no such token exists in this system. An error is a BORDER
 *   COLOUR CHANGE plus a 12px message below it in danger red, carrying a glyph
 *   so the state is never colour alone. A valid field gets no tint at all: the
 *   quiet state is the absence of the loud one. See section 14.
 *
 *   BRAND IS SPENT ONCE. 00-tokens section 3.9 holds the closed list of accent
 *   sites platform-wide, and this file legitimately owns two of them: the TEXT CARET
 *   in a search or command input, and â€” as the one defensible extension â€” the
 *   FILL OF A CHECKED checkbox, radio or switch, which is a control reporting
 *   its own value rather than a decoration. Everything else that used to be
 *   green here â€” the drop zone hover, the input-group addon on focus, the file
 *   trigger hover, the floated label, the selected choice card, the reveal
 *   toggle, the range thumb â€” is now a NEUTRAL wash or a text tier.
 *
 *   MOTION. State changes are fx-dur-fast (100ms), popups enter on
 *   fx-dur-enter (80ms) and leave on fx-dur-exit (60ms) â€” the exit is FASTER
 *   than the entrance on purpose. Nothing in this file sits in the 200 to 400ms
 *   band, which is why fx-dur-slow (250ms) is not read anywhere below.
 *
 *   Comfort is bought with AIR rather than with size, because the type scale is
 *   deliberately small: labels sit one 4px step above their control, the
 *   generosity is spent on the gap BETWEEN field groups, and surface-shaped
 *   controls read the fx-surface-pad-* tokens.
 *
 * NOT IN THIS FILE
 *   Buttons (04-buttons), cards / modals / Bootstrap dropdowns (07-surfaces),
 *   Tabulator and the utility layer (09 / 10), the LeptonX shell (03).
 *   Navigation lives in 06-navigation.css. The .fx-select popup below is a
 *   FORM control's own menu and is owned here; `.dropdown-menu` is not.
 * ========================================================================== */


/* â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 * THE FIELD CONTRACT â€” READ THIS BEFORE STYLING A FIELD IN ANY OTHER LAYER
 * â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * THE DEFECT THIS EXISTS TO END, in the client's own words from a running
 * build: "selectboxes fields, search boxes, text boxes â€¦ they're not following
 * same style, they're looking they from other planet in Tabulator component and
 * abp liptonx." That report was accurate and the cause was architectural, not a
 * matter of tuning. The platform had THREE field systems:
 *
 *     05-forms      40px Â· 8px radius Â· inherited type Â· fx-ctl-pad-x
 *     09-tabulator  fx-grid-target Â· 6px radius Â· fx-grid-meta-text Â· raw
 *                   fx-space-1 / fx-space-2
 *     03-leptonx    its own height, its own radius, its own type, its own pad
 *
 * A search box in a grid toolbar and a search box in a form were therefore two
 * DIFFERENT COMPONENTS THAT RESEMBLED EACH OTHER, which is exactly what reads
 * as "from another planet". There is now ONE system, and a grid field differs
 * from a form field only by SIZE STEP, never by shape.
 *
 * â•â• THE RECIPE â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * To size a field in another layer, redeclare `fx-ctl-h`, `fx-ctl-pad-x`,
 * `fx-ctl-radius` and `fx-ctl-font-size` on your scope.
 *
 * NEVER restate `border-radius`, `min-block-size`, `padding`, `font-size`,
 * `background`, `box-shadow` or the focus treatment. Those belong to 05-forms,
 * and restating them is how three field systems happened in the first place.
 *
 * Better still, opt into a published SIZE STEP and declare nothing at all:
 * `.fx-control-xs`, `.form-control-sm` / `.form-select-sm` / `.fx-control-sm`,
 * `.fx-control-md`, the unclassed default, and `.form-control-lg` /
 * `.form-select-lg` / `.fx-control-lg`. Each is nothing but a block of local
 * redeclarations, which is the pattern every consumer must copy.
 *
 * â•â• WHERE THE LOCALS ARE SET, AND WHY IT DECIDES YOUR SELECTOR â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * THIS IS THE PART THAT IS EASY TO GET WRONG. Custom properties inherit, but
 * the fx-ctl-* family is SET BY SECTION 1 ON THE CONTROL ELEMENT ITSELF, not on
 * a wrapper. So a redeclaration on an ancestor is OVERRIDDEN by section 1 the
 * moment the cascade reaches the control:
 *
 *     .my-toolbar { fx-ctl-h: 32px }        â† WRONG. Section 1 re-sets the
 *                                             local on the input inside it.
 *     .my-toolbar :is(input, select, textarea) { fx-ctl-h: 32px }   â† RIGHT.
 *
 * Target the CONTROL, always. The one exception is a component that has to
 * align a non-control child with the field beside it, such as the floating
 * label in section 13: it reads locals declared on the shared wrapper, and the
 * control ignores those wrapper copies for exactly the reason above.
 *
 * â•â• AND THE ELEMENT MUST BE IN SECTION 1's SELECTOR LIST â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * If it is not, it carries NO fx-ctl-* locals, every declaration reading one is
 * invalid at computed-value time, and the field silently renders unstyled.
 * Section 1 reaches `.form-control`, `.form-select`, `.form-control-plaintext`,
 * bare `textarea`, bare `select`, `input` WITH NO type attribute, and
 * `input[type]` for text, email, password, number, tel, url, search, date,
 * time, datetime-local, month and week. It deliberately does NOT reach
 * checkbox, radio, range, color, file or the button-shaped inputs â€” those are
 * separate control systems with their own local families (see sections 10 and
 * 12), and section 4 of the Z block depends on that exclusion.
 *
 * â•â• THE KNOWN CONSUMERS â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 *   09-tabulator.css
 *     Â· `.frihat-grid-toolbar .frihat-search` and the toolbar's bare
 *       `input[type=search]` / `input[type=text]`  â†’ the md step
 *     Â· `.frihat-grid-toolbar select` (the case, status and court filters)
 *       â†’ the md step
 *     Â· `.tabulator-header-filter` inputs, selects and textareas  â†’ the xs step
 *       or a local redeclaration off fx-grid-target
 *     Â· `.tabulator-cell` editors, and the `.tabulator-editing` variant that
 *       hands the well up to the cell  â†’ the xs step
 *     Â· `.tabulator-footer .tabulator-page-size`  â†’ the md step
 *     Section 1 already parks a boundary rule on `.tabulator :is(â€¦)` that puts
 *     every one of them on the grid step by default. See it below.
 *
 *   03-leptonx.css
 *     Â· `.lpx-menu-filter .menu-filter-input`, the sidebar menu filter. It sits
 *       on the BRAND RAIL, where fx-shadow-well is invisible and fx-color-
 *       field-bg reads as a foreign slab, so it legitimately keeps the rail's
 *       own fill pair and does not read fx-ctl-bg. Its GEOMETRY â€” height,
 *       radius, inline padding and type size â€” is still this file's to give.
 *
 * A consumer that needs a shape no step provides redeclares the four locals
 * and nothing else. A consumer that needs a shape no LOCAL provides has found
 * a gap in this contract: extend the contract here, never fork it there.
 * â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• */


/* â”€â”€ 1) Shared control geometry â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * Component local custom properties. Every text like control reads these, so a
 * page can retune one field by redeclaring a local on a wrapper rather than by
 * rewriting the rule.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.form-control,
.form-select,
.form-control-plaintext,
textarea,
select,
/* AN INPUT WITH NO type ATTRIBUTE IS A TEXT INPUT, and until this selector
 * existed it was the one text field on the platform that carried no fx-ctl-*
 * locals at all. It is not a theoretical case: the vendored Tabulator bundle
 * builds its column TITLE EDITOR as a bare `document.createElement("input")`
 * with no type set, and hand written jQuery dialogs do the same routinely. An
 * element outside this list has no locals, so every declaration reading one is
 * invalid at computed-value time and the field renders unstyled. */
input:not([type]),
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="tel"],
input[type="url"],
input[type="search"],
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"],
input[type="week"] {
    /* 40px, from fx-control-h-lg. THE HEIGHT IS NOT NEGOTIABLE DOWNWARD:
     * fx-control-h-md (32px) is the height of a menu ITEM, a select option and
     * a nav pill â€” things a user clicks once. A text field is a thing the user
     * dwells in, and Linear sizes those a full step larger. */
    --fx-ctl-h: var(--fx-control-h-lg);
    /* 12px. md (16px) is a BUTTON's horizontal padding, where the label is
     * centred and needs shoulders; a field's text starts at the inline start
     * and 16px reads as an indent rather than as padding. */
    --fx-ctl-pad-x: var(--fx-control-pad-x-sm);
    /* Interior block padding is the comfort dial. min-block-size, not a fixed
     * height, so raising this can only ever make a field taller â€” never clip. */
    --fx-ctl-pad-y: var(--fx-space-2);
    /* 8px â€” the Linear input radius. NOT fx-radius-control: a pill shaped text
     * field is a different decision and the reference does not make it. */
    --fx-ctl-radius: var(--fx-radius-md);
    /* THE TYPE SIZE IS A LOCAL, AND ADDING IT IS WHAT LET THE GRID STOP
     * FORKING. A form wants the document's own 15px; a grid toolbar wants 13px
     * and a header filter 12px. Before this local existed a consumer had no way
     * to change the size of the text in a field WITHOUT restating font-size on
     * its own selector, and once a layer restates one geometry property it
     * restates the rest â€” which is the whole mechanism of the three-system
     * defect described at the head of this file.
     *
     * 1em, NOT `inherit`. They compute identically for font-size, because an em
     * on font-size resolves against the PARENT's size, and 1em cannot be a
     * CSS-wide keyword arriving through a var() substitution, which is a corner
     * of the cascade not worth standing on.
     *
     * SO AN UNCLASSED FIELD IS 15px ON A PAGE AND 13px IN A DIALOG, AND THAT IS
     * INTENTIONAL. Recorded 2026-08-03 because it looks like a bug on first
     * reading and is not one. `1em` inherits the context's own type ramp, and
     * both dialog families deliberately set a smaller one:
     *     page body            fx-text-base   15px
     *     .modal-body          fx-text-sm     13px   (07-surfaces 4)
     *     .frihat-dialog       fx-text-sm     13px   (07-surfaces 10)
     * The two dialog families agree with each other, which is the property that
     * makes this consistent rather than broken â€” a hand-built module dialog and
     * an ABP modal render a field at the same size, and that was the whole point
     * of aligning them. A dialog is a denser, more focused surface than a page,
     * so its fields tightening with its prose is the correct behaviour; it is
     * the same reason `fx-ctl-font-size` exists at all rather than a literal.
     *
     * IF A DIALOG FIELD EVER NEEDS THE PAGE SIZE, the answer is a SIZE STEP on
     * the control â€” `.fx-control-lg` is 16px â€” never a `font-size` restated on a
     * dialog scope. Restating it there is the three-field-systems defect at the
     * head of this file, starting over. */
    --fx-ctl-font-size: 1em;
    /* Control leading (1.35), so a multi line field can move to prose leading by
     * redeclaring the local instead of restating line-height. Section 8 is the
     * consumer: a textarea is prose, not a value on one line. */
    --fx-ctl-leading: var(--fx-leading-snug);
    --fx-ctl-bg: var(--fx-color-field-bg);
    --fx-ctl-fg: var(--fx-color-text);
    /* The hint tier. Two grades exist and section 3 explains which field gets
     * which; it is a local so a search or command field can drop to the
     * quaternary grade WITHOUT a second ::placeholder rule in every layer that
     * happens to own one. 09-tabulator used to carry two such copies; both are
     * gone and that file now redeclares this local instead, which is the shape
     * every consumer should copy.
     *
     * IT READS fx-color-text-placeholder, NOT fx-color-text-subtle, AND THAT IS
     * THE WHOLE FIX FOR A DATA-INTEGRITY DEFECT. The two are byte identical at
     * rest. They part company under prefers-contrast: more, where 00-tokens 11
     * collapses every OTHER dimmed grade onto body ink â€” which made a
     * placeholder and a typed value render in exactly the same ink, so an empty
     * field on a case form looked filled. 00-tokens 2.2.2 and 11 carry the
     * ruling and the measurements. A component must never name subtle for a
     * placeholder again; that is what routed this defect through here.
     *
     * â•â• A REQUEST TO POINT THIS AT SUBTLE ARRIVED ON 2026-08-03 AND WAS
     *    DECLINED ON MEASUREMENT. RECORDED SO IT IS NOT RE-RAISED â•â•â•â•â•â•â•â•â•â•â•â•
     * The report was "the placeholder resolves to #74837a and measures 3.98:1
     * against the white focus fill, on EVERY focused field in the product". The
     * first half is a real number; the second half is where it came from. Read
     * off the running app:
     *     ordinary form field   --fx-ctl-placeholder  #58675e   5.89:1 on #ffffff
     *     band search input     --fx-ctl-placeholder  #74837a   4.03:1 on #ffffff
     * #74837a is fx-color-text-faint, and the ONLY thing that sets it is section
     * 3's search and command rule. The measurement was taken on a search box â€”
     * which is the field the reporter was working on â€” and generalised.
     *
     * THE EDIT WOULD ALSO HAVE BEEN A NO-OP THAT REOPENED A LOGGED DEFECT.
     * fx-color-text-placeholder and fx-color-text-subtle are BYTE IDENTICAL at
     * rest â€” both #58675e, verified live â€” so nothing would have moved on any
     * ordinary field. What would have moved is `prefers-contrast: more`, where
     * 00-tokens collapses subtle onto body ink and holds the placeholder grade
     * apart on purpose: an empty field on a case form would once again have
     * rendered in the same ink as a typed value. That is the defect the
     * paragraph above exists to prevent, arriving by a different door.
     *
     * The search tier's own 3.85:1 at rest is a separate, DELIBERATE deviation
     * argued at section 3 with its own guardrail and its own contrast promotion.
     * It is not touched here, and overturning it is a ruling, not a tidy-up. */
    --fx-ctl-placeholder: var(--fx-color-text-placeholder);
    /* `auto` is the caret's own initial value, so the default costs nothing.
     * Section 3 raises it to brand on a search or command field, which is one
     * of this file's two sanctioned brand sites. A consumer that builds a
     * search box out of a type="text" input redeclares this local rather than
     * naming fx-color-primary itself and quietly minting a seventh accent. */
    --fx-ctl-caret: auto;
    /* NO RESTING STROKE. Held in a local so section 14 can turn it into the
     * validation border without any rule below having to restate the shorthand,
     * and so the section Z hardening block can re-assert it in one place. */
    --fx-ctl-border: 0;
    /* The well. Swapped wholesale on hover and focus so the resting depth and
     * the focus fill never have to be concatenated at four different call
     * sites, and so a page can retune one field by redeclaring the local. */
    --fx-ctl-shadow: var(--fx-shadow-well);

    box-sizing: border-box;
    /* NO inline-size HERE â€” see the block immediately after this rule. Full
     * width is a FORM LAYOUT decision, not a control decision, and this
     * selector list reaches every bare control on the platform. */
    min-block-size: var(--fx-ctl-h);
    padding-block: var(--fx-ctl-pad-y);
    padding-inline: var(--fx-ctl-pad-x);
    font-family: inherit;
    font-size: var(--fx-ctl-font-size);
    /* Tokenised, never a literal: the Arabic guard in 00-tokens zeroes this ramp
     * for a joined script. Writing -0.011em here would survive into Arabic and
     * pull the glyphs apart at their joins.
     *
     * DELIBERATELY NOT A LOCAL. Every size step and every consumer wants the
     * same tracking, and a local with no consumer is a name to keep in sync for
     * nothing. If a field ever genuinely needs different tracking, that is the
     * moment to add fx-ctl-tracking, not before. */
    letter-spacing: var(--fx-tracking-ui);
    /* snug (1.35), not normal (1.7): normal is a prose leading and would fight
     * the control height. Prose inside a form uses normal, see help text. */
    line-height: var(--fx-ctl-leading);
    color: var(--fx-ctl-fg);
    caret-color: var(--fx-ctl-caret);
    background-color: var(--fx-ctl-bg);
    background-clip: padding-box;
    /* `border: 0` is written out rather than omitted because Bootstrap, LeptonX
     * and the browser default stylesheet all supply one, and a silently
     * inherited hairline is exactly what the client rejected. */
    border: var(--fx-ctl-border);
    border-radius: var(--fx-ctl-radius);
    box-shadow: var(--fx-ctl-shadow);
    appearance: none;
    /* STATE CHANGES ARE FAST (100ms). Hover, focus and validation are all state
     * changes, so every one of them lands on fx-dur-fast â€” the field answers the
     * pointer rather than easing toward it. NO transform is transitioned: focus
     * no longer moves the control, and a field that drifts under the caret is
     * exactly what the outline model exists to stop. */
    transition:
        background-color var(--fx-dur-fast) var(--fx-ease-standard),
        border-color var(--fx-dur-fast) var(--fx-ease-standard),
        box-shadow var(--fx-dur-fast) var(--fx-ease-standard);
}

/* â”€â”€ 1a) FULL WIDTH IS A FORM LAYOUT DECISION â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * THE DEFECT THIS FIXES
 *   `inline-size: 100%` used to live in the rule above, whose selector list
 *   includes the BARE ELEMENT `select`, `textarea` and every `input[type=â€¦]`.
 *   That is a 0,0,1 claim on every control on the platform, including controls
 *   that are not in a form at all. The visible symptom was the Tabulator footer
 *   page size `<select>` â€” three options, 10/20/50 â€” rendering at 100% and
 *   wrapping onto its own row: `.tabulator-paginator` is a flex container, so a
 *   100% main size resolves to a full width flex basis. The grid toolbar filters
 *   only escaped it because they carry an explicit `flex` basis that outranks
 *   the main size property; that was luck, not design.
 *
 * WHY SCOPING RATHER THAN PATCHING THE ONE CONTROL
 *   A bare control in a toolbar, a grid footer or a pager is not a form field
 *   and must be sized by its content. A control in a FORM is laid out by its
 *   container and should fill the column. Those are two different decisions, so
 *   they get two different rules instead of one rule plus a growing list of
 *   exceptions. Fixing the class of bug also pre-empts the next toolbar control
 *   somebody adds.
 *
 * WHAT STILL FILLS ITS CONTAINER, AND WHY EACH
 *   `.form-control` / `.form-select` / `.form-control-plaintext` â€” explicit
 *   opt-ins into the Bootstrap form system, which makes them 100 percent itself.
 *   Matching it here means our rule and the framework's never disagree.
 *   `textarea` â€” unconditionally, at every size. A multi-line control sized to
 *   its `cols` attribute is never what anyone wants, and there is no toolbar
 *   case for one.
 *   Everything else fills only inside a form CONTEXT. `.frihat-form-grid` is in
 *   that list and is load bearing: the Cases and Courts module dialogs build
 *   their fields as bare `<input>` / `<select>` / `<textarea>` inside a plain
 *   `<div>` inside that grid, with no `.form-control` anywhere, so omitting it
 *   would collapse every field in both modals to its intrinsic width.
 *
 * SPECIFICITY: `:is()` takes the specificity of its most specific argument, so
 * this lands at 0,2,1 and comfortably clears the bare element selectors. It does
 * not contest section Z, which never restated `inline-size`.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.form-control,
.form-select,
.form-control-plaintext,
textarea,
:is(form, .fx-field, .fx-form-grid, .frihat-form-grid, .form-group, .form-floating, .input-group, .mb-3)
    :is(select,
        input:not([type]),
        input[type="text"],
        input[type="email"],
        input[type="password"],
        input[type="number"],
        input[type="tel"],
        input[type="url"],
        input[type="search"],
        input[type="date"],
        input[type="time"],
        input[type="datetime-local"],
        input[type="month"],
        input[type="week"]) {
    inline-size: 100%;
}

/* â”€â”€ 1b) THE SIZE STEPS â€” THE ONLY SANCTIONED WAY TO VARY A FIELD â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * Every step below is NOTHING BUT A BLOCK OF LOCAL REDECLARATIONS. Not one of
 * them restates border-radius, min-block-size, padding, font-size, background,
 * box-shadow or a focus treatment, and that is not tidiness â€” it is the whole
 * contract, demonstrated. A consumer in 09-tabulator or 03-leptonx copies this
 * shape exactly, on a selector that matches the CONTROL element.
 *
 * THE LADDER, and what each rung is for:
 *
 *   .fx-control-xs        24px fine / 28px coarse Â· 8px pad Â· 4px radius Â· 12px
 *                         A field inside a data-dense row: a grid header filter,
 *                         a cell editor. The smallest field this system draws.
 *   .form-control-sm      28 / 32 Â· 10px pad Â· 6px radius Â· 13px
 *   .form-select-sm       A compact form, a dialog filter strip, a DataTables
 *   .fx-control-sm        search box.
 *   .fx-control-md        32 / 40 Â· 12px pad Â· 8px radius Â· 13px
 *                         A field in a TOOLBAR beside 32px buttons: the grid
 *                         toolbar search, the toolbar filter selects, the pager
 *                         page size. 32px is the platform's default control
 *                         height, so a field on this step lines up with every
 *                         button next to it without anybody measuring.
 *   (no class)            40 / 44 Â· 12px pad Â· 8px radius Â· document size
 *                         THE FORM FIELD. The thing a user dwells in. See the
 *                         height note in section 1 for why it is not 32px.
 *   .form-control-lg      44 / 48 Â· 16px pad Â· 8px radius Â· 16px
 *   .form-select-lg       A hero field: the login form, a single-question page.
 *   .fx-control-lg
 *
 * EVERY STEP STAYS ON A RADIUS THE SHAPE EARNS. xs drops to fx-radius-xs and sm
 * to fx-radius-sm because a 4px corner on a 40px box reads as unfinished while
 * an 8px corner on a 24px box reads as a lozenge, but md and lg both hold
 * fx-radius-md: past 32px the step is chosen by what the element IS, not by how
 * big it happens to be, and fx-radius-lg belongs to panels. Nothing here is
 * ever fx-radius-control â€” the pill belongs to things that are buttons by role.
 *
 * EVERY HEIGHT IS A CONTROL TOKEN, so the coarse pointer tier in 00-tokens
 * moves the whole ladder and no step below states a height of its own. The one
 * pointer query this file does write is section 1d, and it is a TYPE floor
 * rather than a height, for a reason recorded there: 00-tokens' coarse tier
 * restates every control height and no fx-text-* token at all. Even xs
 * lands on 24px, which is the SC 2.5.8 floor exactly, and 28px on touch.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* EVERY RUNG BELOW REPEATS ITS OWN CLASS, AND THE LADDER DOES NOT WORK WITHOUT
 * IT. THIS IS A FIX, NOT A FLOURISH.
 *
 * Section 1 declares the fx-ctl-* locals on a list that includes `.form-control`
 * at (0,1,0) but also `input[type="text"]` and its nine siblings at (0,1,1). A
 * size class written once is (0,1,0) â€” so on an INPUT it loses to the very rule
 * it is trying to retune, and the step silently does nothing.
 *
 * Measured in the running app before the fix: `.form-control-lg` and
 * `.fx-control-sm` both rendered a 40px input, the unclassed default. The same
 * classes on a `<textarea>` or a `<select>` worked correctly, because those bare
 * selectors are (0,0,1) and lose to a class. So the ladder appeared to function
 * everywhere it was first tested and was inert on the one element type most
 * forms are built from â€” including this file's own named example, a hero field
 * on the login form, which could not be used.
 *
 * Doubling the class takes each rung to (0,2,0), which clears (0,1,1) without
 * touching section 1, without a flag, and without wrapping that selector list in
 * :where() â€” which would have zeroed it and handed every bare element back to
 * Bootstrap's own .form-control. It is the same class repetition idiom used to
 * out-specify vendor sheets elsewhere in this system.
 *
 * A NEW RUNG MUST DOUBLE ITS CLASS TOO. A rung written once will look correct in
 * a select and do nothing in an input, which is the hardest kind of bug to see.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.fx-control-xs.fx-control-xs {
    --fx-ctl-h: var(--fx-control-h-xs);      /* 24px fine / 28px coarse */
    --fx-ctl-pad-x: var(--fx-space-2);       /* 8px â€” under the pad-x ladder's
                                              * own floor on purpose: 10px in a
                                              * 24px box leaves no measure. */
    --fx-ctl-pad-y: var(--fx-space-1);
    --fx-ctl-radius: var(--fx-radius-xs);
    --fx-ctl-font-size: var(--fx-text-xs);   /* 12px, the grid meta step */
}

.form-control-sm.form-control-sm,
.form-select-sm.form-select-sm,
.fx-control-sm.fx-control-sm {
    /* control-h-sm (28px), NOT control-h-md. The small variant was landing on
       the md step, which is the height of a menu item and only 4px under the
       40px default â€” close enough that a "small" DataTables search box read as
       full height beside the grid. 28px still clears the 24px SC 2.5.8 floor,
       and the coarse pointer tier lifts it to 32px automatically. */
    --fx-ctl-h: var(--fx-control-h-sm);      /* 28px fine / 32px coarse */
    --fx-ctl-pad-x: var(--fx-control-pad-x-xs);
    --fx-ctl-radius: var(--fx-radius-sm);
    --fx-ctl-pad-y: var(--fx-space-1);
    --fx-ctl-font-size: var(--fx-text-sm);
}

/* THE MISSING RUNG, AND THE ONE THE GRID HAD TO FORK TO GET.
 *
 * There was no 32px step. A toolbar wants its search box the same height as the
 * buttons beside it, which are fx-control-h-md, and the ladder offered only
 * 28px (visibly short) or 40px (visibly tall). So 09-tabulator wrote its own
 * `min-block-size: max(fx-grid-target, fx-control-h-md)` with its own padding
 * and its own type size, and from there the toolbar search and the form search
 * were two components. This rung is what that layer opts into instead. */
.fx-control-md.fx-control-md {
    --fx-ctl-h: var(--fx-control-h-md);      /* 32px fine / 40px coarse */
    --fx-ctl-pad-x: var(--fx-control-pad-x-sm);
    /* space-1, not space-2. 8px of block padding around a 13px line box demands
     * 33.5px and the field would overshoot the 32px it is here to match;
     * min-block-size can grow a control but never shrink it. */
    --fx-ctl-pad-y: var(--fx-space-1);
    --fx-ctl-radius: var(--fx-radius-md);
    --fx-ctl-font-size: var(--fx-text-sm);
}

.form-control-lg.form-control-lg,
.form-select-lg.form-select-lg,
.fx-control-lg.fx-control-lg {
    --fx-ctl-h: var(--fx-control-h-xl);      /* 44px */
    --fx-ctl-pad-x: var(--fx-control-pad-x-md);
    --fx-ctl-radius: var(--fx-radius-md);
    --fx-ctl-pad-y: var(--fx-space-3);
    --fx-ctl-font-size: var(--fx-text-lg);
}

/* â”€â”€ 1c) THE GRID BOUNDARY â€” NOW A SIZE STEP, NOT A DIFFERENT SYSTEM â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * WHAT WAS HERE, AND WHY IT WAS THE PROBLEM RATHER THAN THE FIX:
 *
 *     .tabulator :is(input, select, textarea) {
 *         min-block-size: 0; padding-block: 0; box-shadow: none;
 *     }
 *
 * It read as a polite boundary â€” "the grid owns its own editors" â€” and it was
 * the sentence that authorised a second field system. It did not hand the grid
 * a smaller field; it handed the grid NOTHING, so 09-tabulator had to rebuild
 * the fill, the depth, the radius, the padding and the type from scratch on
 * three separate selectors, and the moment it did that the grid's fields could
 * drift from the platform's without anybody editing this file. `box-shadow:
 * none` was the worst line of the three: fx-shadow-well is the SC 1.4.11
 * carrier for every borderless control on the platform, so flattening it inside
 * the grid made those fields non-conformant, not merely different.
 *
 * WHAT IS HERE NOW is the contract applied to the grid: five local
 * redeclarations and not one geometry property. It is the SAME COMPONENT as a
 * form field, at a smaller size â€” which is the entire point.
 *
 * IT IS NOT "THE xs STEP", AND THIS NOTE SAID SO UNTIL 2026-08-03. Corrected
 * because the sentence was load bearing in the wrong direction: a reader who
 * believed it would "fix" a drift by pointing the block at `fx-control-h-xs` and
 * would shrink every grid field by 4px. THE GRID STEP SITS BETWEEN xs AND sm,
 * and it is deliberately a blend rather than a rung:
 *
 *     height   fx-grid-target = max(24px, fx-control-h-sm)
 *                             = 28px fine / 32px coarse   â† the SM height
 *     radius   fx-radius-sm                               â† the SM corner
 *     pad-x    fx-space-2 (8px)                           â† the XS padding
 *     type     fx-grid-meta-text = fx-text-xs (12px)      â† the XS type
 *
 * The SILHOUETTE is sm and the INTERIOR is xs, which is what a data-dense row
 * actually wants: enough box to clear the 24px SC 2.5.8 floor with real headroom
 * (28px, not 24px exactly), and tight enough type and padding to keep a header
 * filter from dominating the column it filters. The `max(24px, â€¦)` in 09's token
 * is a floor guarantee, not the operative value â€” it only ever binds if the
 * control ladder is retuned below 24px.
 *
 * Both halves come from 09-tabulator's own tokens rather than from named rungs
 * here, so a coarse pointer still lifts the whole thing through
 * `fx-control-h-sm` and the grid keeps one place to tune its density.
 *
 * SELECTION CONTROLS ARE EXCLUDED. A checkbox and a radio are a different
 * control system with their own fx-check-* family (section 12), and their
 * silhouette is load bearing: routing a grid checkbox through fx-ctl-radius
 * would square a radio button, which section 12 explains is a defect and not a
 * style opinion.
 *
 * The fallbacks are real: `.tabulator` without `.frihat-grid` is a plain
 * vendored grid, and 09 declares fx-grid-target and fx-grid-meta-text on
 * `.frihat-grid.tabulator` only. */
.tabulator :is(input:not([type="checkbox"], [type="radio"]), select, textarea) {
    --fx-ctl-h: var(--fx-grid-target, var(--fx-control-h-xs));
    --fx-ctl-pad-x: var(--fx-space-2);
    --fx-ctl-pad-y: var(--fx-space-1);
    --fx-ctl-radius: var(--fx-radius-sm);
    --fx-ctl-font-size: var(--fx-grid-meta-text, var(--fx-text-xs));
}


/* â”€â”€ 1d) THE 16px TOUCH FLOOR â€” THE ONE POINTER QUERY THIS FILE OWNS â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * THE DEFECT: iOS Safari ZOOMS THE VIEWPORT when a user focuses an input whose
 * computed font-size is under 16px. It is not a preference and there is no way
 * to opt out of it that this platform is willing to take, because the only
 * mechanism is `user-scalable=no` on the viewport meta, which disables pinch
 * zoom for everyone and fails SC 1.4.4. So the page lurches and re-centres the
 * moment a thumb lands on a field, and on the login form â€” the front door, one
 * field, nothing else on screen â€” that is the first thing the product does.
 *
 * MEASURED, and the numbers are the type ramp doing exactly what it is designed
 * to do: fx-ctl-font-size is `1em`, which inherits the document ramp, and
 * fx-text-base is a clamp that resolves to 15px at desktop and 14.007px at a
 * 371px viewport. A phone therefore sits at the BOTTOM of a ramp whose top is
 * still a pixel under the threshold. No amount of tuning the clamp fixes this
 * without making desktop type larger than the design calls for, which is why the
 * answer is a floor rather than a new base size.
 *
 * â•â• WHY THIS IS GATED ON THE POINTER AND NOT APPLIED EVERYWHERE â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * 16px is a browser behaviour threshold, not a design decision, and it is the
 * wrong size for this platform's type scale: a 16px value in a 40px field on a
 * dense desktop case form is a full step over the 15px prose beside it and reads
 * as a form built for a different product. `pointer: coarse` is the narrowest
 * gate that covers every device the behaviour exists on, and it is the SAME gate
 * the control ladder already steps through in 00-tokens, so a touch field grows
 * its box and its type together rather than gaining type inside a box sized for
 * something smaller.
 *
 * â•â• AND WHY IT IS THE BASE LOCAL ONLY â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * This rule matches section 1's list at its weight, so it moves THE FORM FIELD â€”
 * the unclassed default, which is what the login form, the ABP account pages and
 * every module dialog emit. It deliberately does NOT reach the published size
 * steps: each of those is (0,2,0) and out-ranks this by design, so a field that
 * an author explicitly put on the xs, sm, md or lg step keeps the size the
 * author asked for.
 *
 * THAT IS A REAL TRADE AND IT IS BEING MADE ON PURPOSE. A grid header filter or
 * a cell editor on a phone still sits at 12px and will still trigger the zoom.
 * Floating the whole ladder to 16px on touch would make a data grid unreadable
 * on the device with the least room for it â€” four columns of 16px type inside a
 * 28px row â€” and a grid is a surface a user READS and filters, not one they dwell
 * in typing. The form field is the control this defect actually hurts, and it is
 * the one this rule moves. If a dense touch grid ever needs the floor too, the
 * fix is a coarse tier on fx-grid-meta-text in 09-tabulator, at that layer's own
 * scope, not a widened query here.
 *
 * â•â• THE ONE POINTER QUERY, AND THE RULE IT IS AN EXCEPTION TO â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * Section 16.1 says this file writes no coarse-pointer override, and that rule
 * is about TARGET SIZE: every height here is a control token, so 00-tokens moves
 * the whole ladder and a second query would be a competing copy of a decision the
 * token layer already owns. The type ramp is different â€” 00-tokens' coarse tier
 * restates the control heights, the paddings, the row heights and the icon sizes,
 * and it deliberately restates NO fx-text-* token, so there is nothing at that
 * layer for a derivation to read. Until there is, the floor lives here, written
 * the way this file asks every consumer to write one: a local redeclaration and
 * not a single geometry property. 09-tabulator already carries the same shape for
 * fx-grid-target, which is the precedent this follows.
 *
 * max(), NOT A FLAT 16px, so the floor is a floor. If the type ramp is ever
 * raised past 16px the field follows it up instead of being pinned back down to
 * a threshold that stopped binding.
 *
 * A LITERAL PIXEL VALUE IS CORRECT HERE and is not a token that went missing.
 * 16px is a number Safari owns, not a rung on this platform's scale, and minting
 * an fx-text-* token for it would put a foreign constant into the design ramp
 * where the next person to tune the scale would move it. It is the same
 * reasoning that leaves `1.5rem` and `12ch` written literally elsewhere in this
 * file: a threshold is documented at its call site, never scaled with the system.
 *
 * NOT VERIFIABLE IN THIS ENVIRONMENT. Desktop Chrome does not reproduce the iOS
 * zoom, and emulating a coarse pointer proves only that the local changed. What
 * is measurable here is the computed font-size, and that is all this note claims.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
@media (pointer: coarse) {
    .form-control,
    .form-select,
    .form-control-plaintext,
    textarea,
    select,
    input:not([type]),
    input[type="text"],
    input[type="email"],
    input[type="password"],
    input[type="number"],
    input[type="tel"],
    input[type="url"],
    input[type="search"],
    input[type="date"],
    input[type="time"],
    input[type="datetime-local"],
    input[type="month"],
    input[type="week"] {
        --fx-ctl-font-size: max(1em, 16px);
    }
}


/* â”€â”€ 2) Interaction states â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * Hover LIGHTENS THE FILL. There is no boundary left to strengthen, so the
 * response is the well opening up one step: a lighter fill in light mode, a
 * brighter one in dark, both supplied by fx-color-field-bg-hover. Gated behind
 * any-hover so a touch device never latches a hover fill after a tap.
 *
 * TOKEN NAMES ARE fx-color-field-bg, -bg-hover and -bg-focus. An earlier pass of
 * this file spelled the last two fx-color-field-hover and fx-color-field-focus,
 * which are not declared anywhere in 00-tokens.css. An undefined custom property
 * makes the declaration that reads it invalid at computed-value time, so
 * background-color fell back to transparent and EVERY hover and focus fill in
 * the form layer silently did nothing. Spell them in full.
 *
 * FOCUS BRIGHTENS AND NOTHING ELSE MOVES. The fill goes to
 * fx-color-field-bg-focus and the well STAYS â€” a focused field must remain
 * identifiable as a field. The indicator itself is the outline from 01-base
 * section 11, which every focusable thing in the platform shares.
 *
 * WHAT CARRIES THE 3:1. Two separate obligations, two separate carriers:
 *   Â· SC 1.4.11 component identification â†’ fx-shadow-well, at rest and in every
 *     state except disabled. Never remove it to "clean up" a control.
 *   Â· SC 2.4.11 / 2.4.13 focus appearance â†’ the 2px outline at 2px offset,
 *     measured at 3.47:1 (light, on the page) and 5.52:1 (dark).
 * The fill change is decoration and carries neither.
 *
 * â•â• THE OPT-OUT CONTRACT HOLDS AT REST ONLY, AND THIS PAIR IS THE REASON â•â•â•â•
 * RULED 2026-08-03, after the promise was tested and failed.
 *
 * 01-base paints `background-color: var(--fx-ctl-bg, <state token>)` and tells a
 * component it can leave the page field system by MOVING THE LOCAL rather than
 * out-specifying a painted property. At rest that is true and it is a good
 * contract. In the two states below it is not, and no amount of care at the
 * consumer's end makes it true: this rule and the focus rule under it BOTH
 * redeclare `--fx-ctl-bg` at (0,4,1), and 05-forms loads after 03-leptonx, so a
 * component setting the local at (0,2,0) in its own layer is simply overwritten
 * the moment a pointer arrives. Proven live â€” `--fx-ctl-bg: transparent` at
 * (0,2,0) still computed #fbfdf9 on hover â€” which is why the band search had to
 * be answered at the PAINT rather than at the local.
 *
 * THE WEIGHTS ARE NOT THE THING TO CHANGE, and that is the justification for
 * narrowing the promise instead of honouring it. Both (0,4,1)s are load bearing
 * and both are recent fixes, not accidents: the guards on the hover rule are
 * what make it CORRECT (a disabled or readonly control must never take a hover
 * fill), and the matching armour on the focus rule is what stopped focus losing
 * to hover â€” the defect measured on /Account/Manage and written out in full
 * below this. Lowering either arm reopens a defect that was closed the same day.
 * Lowering BOTH keeps them level with each other but drops them under the guards
 * they need. There is no weight for this pair that is simultaneously correct and
 * beatable from a component layer.
 *
 * SO THE CONTRACT IS: THE LOCAL IS A REST-STATE CONTRACT. A component that must
 * hold its own fill through hover and focus states them itself, on its own
 * selector, in the same states â€” which is what `.form-control-plaintext` and the
 * tabulator cell editor already do, and it costs them two extra rules rather
 * than a specificity war. 01-base's own sentence still claims the broader
 * promise; narrowing it there belongs to that file's owner and is reported
 * upward rather than reached into from here. Until it is narrowed, THIS comment
 * is the accurate one â€” the code below is the evidence.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
@media (any-hover: hover) {
    :is(.form-control, .form-select, textarea, select, input:not([type]),
        input[type="text"], input[type="email"], input[type="password"],
        input[type="number"], input[type="tel"], input[type="url"],
        input[type="search"], input[type="date"], input[type="time"],
        input[type="datetime-local"], input[type="month"], input[type="week"]
       ):hover:not(:disabled):not([readonly]) {
        --fx-ctl-bg: var(--fx-color-field-bg-hover);
    }
}

/* â•â• THE GUARDS ARE HERE TO OUT-WEIGH HOVER, AND WITHOUT THEM FOCUS LOST â•â•â•â•â•
 *
 * MEASURED ON /Account/Manage, 2026-08-03, clicking into a field with the mouse
 * and leaving the pointer on it:
 *     expected  fx-color-field-bg-focus   #ffffff   1.046:1 on the card
 *     rendered  fx-color-field-bg-hover   #fbfdf9   1.022:1
 * The focused field kept the HOVER fill, so "focus brightens" â€” the promise this
 * section is written around â€” was broken in the single most common way a mouse
 * user focuses a field. It only came right when the pointer moved away, which is
 * why it reads as a flicker on mouse-out rather than as a missing state.
 *
 * THE ARITHMETIC. `:is()` and `:not()` each contribute the weight of their most
 * specific argument, and this list's heaviest arm is `input[type="text"]` at
 * (0,1,1). So the hover rule above was
 *     :is(list) + :hover + :not(:disabled) + :not([readonly])  = (0,4,1)
 * against a focus rule of
 *     :is(list) + :is(:focus, :focus-visible)                  = (0,2,1).
 * Two whole classes apart. Nothing was mis-declared; the guards that make the
 * hover rule CORRECT are also what made it heavy, and the focus rule was never
 * given the same armour.
 *
 * WHY GUARDS RATHER THAN A DOUBLED SELECTOR. They are true, and they are the
 * two states that must never take a focus fill anyway: a `:disabled` control is
 * inert, and `.disabled` is the cosmetic twin this file's own disabled rule in
 * this section already recognises alongside it. Written this way the rule reads
 * as a statement about the control rather than as a specificity trick, and it
 * lands at (0,4,1) â€” level with hover, and later in the file, so source order
 * settles it in focus's favour. That is the same tie-break section 11 relies on
 * between the input group's hover and its :focus-within, so the two field shapes
 * now resolve the pair identically instead of opposite ways round.
 *
 * READONLY IS DELIBERATELY NOT GUARDED. A readonly field is focusable, a lawyer
 * tabs into one to read and copy a value, and it must show where the caret is.
 * It is absent from the hover rule for the opposite reason â€” there is nothing to
 * invite a pointer into â€” so the two lists differ by exactly one arm, on purpose.
 */
:is(.form-control, .form-select, textarea, select, input:not([type]),
    input[type="text"], input[type="email"], input[type="password"],
    input[type="number"], input[type="tel"], input[type="url"],
    input[type="search"], input[type="date"], input[type="time"],
    input[type="datetime-local"], input[type="month"], input[type="week"]
   ):is(:focus, :focus-visible):not(:disabled):not(.disabled) {
    --fx-ctl-bg: var(--fx-color-field-bg-focus);
}

/* THE FIELD'S OUTLINE IS TRANSPARENT, AND THAT IS NOT THE SAME AS ABSENT.
 *
 * OWNER DECISION, 2026-08-29. A 2px ring standing 2px off the control was
 * rejected: it fences the field instead of choosing it, and on a form of eight
 * it is the loudest thing on the screen. Fields now take the hugging glow
 * (fx-shadow-field-focus, declared in 00-tokens with the full argument); the
 * outline stays declared, at the same width and offset, painted in nothing.
 *
 * WHY KEEP IT AT ALL. Forced-colours mode DROPS EVERY box-shadow in the
 * document. A field whose only indicator was a shadow would be focusable with
 * no visible focus at all for exactly the users least able to afford it. A
 * transparent outline keeps the geometry reserved, and section 16's
 * forced-colours block hands it back a system colour, so the ring returns the
 * moment the shadow model stops working. Deleting this declaration would look
 * like tidying and would be an accessibility regression.
 *
 * ALSO STILL INSURANCE against the vendored sheets in this bundle that set
 * `outline: none` on :focus for form controls â€” it is restated here rather than
 * left to 01-base for that reason, unchanged.
 *
 * THIS RULE IS FIELDS ONLY. 01-base section 11's universal `:focus-visible`
 * outline is untouched, so buttons, links, menu items, checkboxes and grid
 * cells keep the ring. That asymmetry is the decision, not an oversight: an
 * outline is the right indicator for a thing you press, and a glow for a thing
 * you type into. */
:is(.form-control, .form-select, textarea, select, input):focus-visible {
    outline: var(--fx-focus-width) solid transparent;
    outline-offset: var(--fx-focus-offset);
}

/* â•â• THE WELL, RE-ASSERTED ON FOCUS â€” BOOTSTRAP'S BLUE GLOW WAS WINNING â•â•â•â•â•
 *
 * MEASURED 2026-08-03, focusing a field in the ABP new-user dialog:
 *     box-shadow   rgba(13, 110, 253, 0.25) 0 0 0 4px
 * That is Bootstrap's stock focus glow, in Bootstrap's stock BLUE â€” a hue this
 * design system does not contain anywhere, on any surface, in either theme. And
 * `box-shadow` REPLACES rather than composes, so the three-layer well was not
 * merely tinted, it was DELETED: a focused field in a modal had no fill step
 * worth 3:1 and no depth, which is the SC 1.4.11 identification cue gone in the
 * one state where the user is certain to be looking at the control.
 *
 * WHY IT HAD NEVER BEEN SEEN. Bootstrap's rule is `.form-control:focus` at
 * (0,2,0); this file's paint is section 1's `background`/`box-shadow` pair at
 * (0,1,0) on the class arms and (0,1,1) on the type arms. Bootstrap wins both.
 * Section Z restates the same paint at (0,3,0) and beats it â€” but section Z is
 * scoped `.lpx-content`, and EVERY ABP MODAL IS APPENDED TO `body`, outside that
 * scope. So the defect was invisible on every page of the app and present in
 * every dialog, which is where most of this platform's data entry happens.
 * Section Z.1 records this failure mode from the inside; this is the same shape
 * seen from the outside, and the answer is the same: fix it at the tier that is
 * universal rather than by widening the theme scope.
 *
 * SPECIFICITY. `:is()` takes its heaviest argument, so the `input:not([â€¦])` arm
 * puts this at (0,2,1) â€” one element step over Bootstrap's (0,2,0), which
 * settles it without a flag and without touching section 1's cheap base rule.
 *
 * `:focus` AS WELL AS `:focus-visible`, because the rule being answered is
 * `:focus`. A pointer user gets no outline by design, and it would be perverse
 * for them to be the ones who lose the well to a blue glow instead.
 *
 * THE EXCLUSION LIST IS THE ONE SECTION Z USES, AND FOR THE FIRST OF ITS TWO
 * REASONS. Checkbox, radio, range and the button-shaped inputs carry NO fx-ctl-*
 * locals â€” section 1 deliberately leaves them out â€” so `var(--fx-ctl-shadow)`
 * would be invalid at computed-value time on them and box-shadow would fall back
 * to `none`, deleting the checkbox's boundary ring AND its well at the exact
 * moment it is focused. Colour and file are excluded for section Z's second
 * reason: they own their own focus rules in 10.4 and 10.5.
 *
 * IT READS THE LOCAL, so it costs the input group nothing: section 11 hands the
 * member `--fx-ctl-shadow: none` and this rule faithfully paints none, leaving
 * the assembly's own well to carry the control. Same for a grid cell editor,
 * whose focus swaps the local to fx-shadow-focus in 09-tabulator. */
/* â•â• AND SINCE 2026-08-29 IT ALSO CARRIES THE GLOW â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * The ring moved from `outline` to this box-shadow list when the owner rejected
 * the detached outline on fields (see the rule above and the token's own header
 * in 00-tokens). The glow is listed FIRST so it paints on top of the well's
 * edge, and the well is listed second so it SURVIVES â€” a focused field must
 * still read as a field under SC 1.4.11, which is the whole reason this rule
 * existed before the glow was added to it.
 *
 * THE FALLBACK CHAIN IS THE WHOLE COMPATIBILITY STORY, and it is worth reading
 * as one expression. `var(--fx-ctl-shadow-focus, A, B)` means: a component that
 * declares fx-ctl-shadow-focus gets exactly what it asked for; everything else
 * gets the glow composed over its own well.
 *
 * A COMPONENT THAT SETS `--fx-ctl-shadow: none` NEEDS NO EDIT. The fallback
 * expands to `glow, none`, which is invalid at computed-value time, so
 * box-shadow computes to its initial value â€” none â€” which is precisely what
 * such a component asked for. That is the input-group MEMBER and the grid cell
 * editor: both deliberately surrender their own indicator because the assembly
 * around them carries it. Relying on invalid-at-computed-value-time is usually
 * a smell; here the fallback and the intent coincide exactly, and stating it
 * beats fourteen scattered `--fx-ctl-shadow-focus: none` declarations that
 * would each have to be kept in step with their well by hand. */
:is(.form-control, .form-select, textarea, select,
    input:not([type="checkbox"], [type="radio"], [type="range"], [type="color"], [type="file"], [type="image"], [type="submit"], [type="button"], [type="reset"])
   ):is(:focus, :focus-visible) {
    box-shadow: var(--fx-ctl-shadow-focus, var(--fx-shadow-field-focus), var(--fx-ctl-shadow));
}


/* â”€â”€ 2.1) The focus bloom is GONE â€” read this before reinstating anything â”€â”€â”€â”€
 *
 * WHAT WAS HERE. An ::after overlay on .form-floating, .fx-file-drop and
 * .fx-check-card that painted fx-shadow-focus-glow and ran the fx-focus-bloom
 * keyframe, plus a set of companion rules that made the control surrender its
 * own halo and its own lift so the two copies would not composite. Roughly
 * seventy lines of machinery whose entire purpose was to make a glow grow
 * without dragging the value text with it.
 *
 * WHY IT IS GONE. Since the 2026-08-02 retune the platform has exactly one
 * focus indicator: `outline: 2px solid fx-color-focus-ring` at 2px offset,
 * declared once in 01-base section 11. An outline follows the element's own
 * border-radius, is painted outside the box so it cannot be clipped, survives
 * forced-colours mode where every box-shadow is dropped, and needs no overlay,
 * no keyframe, no z-index and no lift. The bloom was decoration attached to an
 * accessibility affordance, and it made focus read as a state change rather
 * than as a cursor position. fx-shadow-focus-glow and fx-lift-focus are both
 * deprecated in 00-tokens and neither is referenced anywhere in this file.
 *
 * DO NOT REINTRODUCE A box-shadow FOCUS RING HERE. The one sanctioned
 * box-shadow expression of focus is fx-shadow-focus, and it exists solely for a
 * component that CLIPS ITS OWN OVERFLOW and therefore cannot render an outline
 * at a positive offset. Exactly one component in this file is in that position:
 * .input-group, which must keep overflow: hidden to hold its members' fills
 * inside the assembly's corners. See section 11.
 *
 * THE ROVING-FOCUS EXCEPTION. Inside a widget with roving tabindex â€” the
 * .fx-select popup in section 7, a listbox, a menu â€” the focused ITEM must NOT
 * draw a ring. A ring inside a popup traces a second rounded rectangle 2px
 * outside an item that sits in a container only 4px wider than it is, and the
 * result reads as a rendering fault. Those items take `outline: none` plus
 * `background: var(--fx-color-active)`, and the ring stays on the container the
 * user actually tabbed to. That is the ONLY sanctioned suppression of a focus
 * ring in this system, and section 7.3 is the only place this file uses it.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.fx-file-drop,
.fx-check-card {
    /* Retained: both are stacking contexts for their own content, and the drop
     * zone positions its dragover state against this. .form-floating declares
     * its own in section 13. */
    position: relative;
}

/* Disabled reads as inert: the surface is sunken and the text is dimmed.
 * Readonly reads as informative: the value keeps full text contrast, only the
 * frame softens, because a readonly value is still information the lawyer must
 * be able to read and copy. The two must never look the same. */
:is(.form-control, .form-select, textarea, select, input):disabled,
:is(.form-control, .form-select, textarea, select, input).disabled,
fieldset:disabled :is(.form-control, .form-select, textarea, select, input) {
    /* Through the local, not as a bare `color`. A consumer that redeclares
     * fx-ctl-fg on its own scope would otherwise find the disabled state was
     * the one place its colour did not reach. */
    --fx-ctl-fg: var(--fx-color-disabled-fg);
    --fx-ctl-bg: var(--fx-color-disabled-bg);
    /* The well goes FLAT. Depth is what says "you can type in here", so removing
     * it is the disabled signal, and a disabled control is explicitly exempt
     * from the SC 1.4.11 identification obligation. */
    --fx-ctl-shadow: none;
    cursor: not-allowed;
    opacity: 1; /* opacity would also fade the fill below its own contrast floor */
}

/* â•â• THE SAME DISABLED FILL, ONE CLASS HEAVIER, BECAUSE OF DIALOGS â•â•â•â•â•â•â•â•â•â•
 *
 * FOUND 2026-08-03 IN A RUNNING MODAL. Bootstrap paints `.form-control:disabled`
 * at (0,2,0) from `--bs-secondary-bg`, which 03-leptonx maps to LEVEL 2 â€” the
 * ENABLED resting fill. The rule above is (0,1,1) and 01-base 13 is (0,1,1);
 * both lose. Section Z's hardening covers it on the page, which is precisely why
 * this was invisible everywhere except inside a dialog:
 *
 *     painted in a modal   #1b291f dark / #f7fbf5 light   1.051 / 1.046
 *     the local correctly  #1a251d dark / #e9eee7 light   1.007 / 1.125
 *
 * i.e. a disabled field looked ENABLED in every dialog on the platform. Same
 * modal-scoping trap the Bootstrap focus glow hits, a different property.
 *
 * 01-base IS DELIBERATELY LEFT ALONE. Raising its weight would drag
 * `button:disabled` and `select:disabled` along with it unevenly, so the twin
 * belongs here, where the arms are already enumerated.
 *
 * WEIGHT, WRITTEN OUT BECAUSE IT IS THE WHOLE POINT. `:is()` takes its most
 * specific argument â€” `.form-control` at (0,1,0) â€” and the `input:not(...)` arm
 * is (0,1,1) through `:not()`'s own most specific argument, so the list is
 * (0,1,1); `:disabled` adds a class point for (0,2,1). That clears Bootstrap's
 * (0,2,0) on weight alone, with no importance flag, and stops one point short of
 * anything that would disturb a heavier deliberate override.
 *
 * IT READS THE LOCAL, NOT THE TOKEN, so 09-tabulator's inline cell editors â€”
 * which set `--fx-ctl-bg: transparent` on their own scope â€” still win here
 * instead of finding disabled was the one state that ignored them. The input
 * exclusion list is the same one section 1 uses: a checkbox, radio, range,
 * colour, file, image or button has its own disabled treatment and must not be
 * handed a text field's fill. */
:is(.form-control, .form-select, textarea, select,
    input:not([type="checkbox"], [type="radio"], [type="range"], [type="color"], [type="file"], [type="image"], [type="submit"], [type="button"], [type="reset"])
   ):disabled {
    background-color: var(--fx-ctl-bg);
}

/* Readonly reads as INFORMATIVE, not inert: the value keeps full text contrast
 * because a lawyer must still be able to read and copy it. It is told apart from
 * disabled by three things â€” full strength text, a surface rather than a
 * disabled fill, and a default cursor instead of not-allowed. */
:is(.form-control, textarea, input)[readonly] {
    --fx-ctl-fg: var(--fx-color-text);
    --fx-ctl-bg: var(--fx-color-surface-sunken);
    /* â•â• THE WELL STAYS. RULED 2026-08-03 â€” READONLY IS NOT EXEMPT FROM
     *    SC 1.4.11, AND THIS LINE USED TO SAY `none` â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
     *
     * The exemption in 1.4.11 covers an INACTIVE component. A readonly field is
     * not inactive: it is in the tab order, it takes a caret, and it is tabbed
     * into for exactly the reason the comment above states â€” so a lawyer can
     * read and copy the value. This file argues that case itself two rules up
     * and then, by flattening the well, removed the boundary the argument
     * depends on. Disabled stays exempt and stays flat; that is the rule this
     * one is being told apart from, not a precedent to copy.
     *
     * IT BECAME LOAD BEARING WITH THE LAYERING FIX. Before it, hover repainted a
     * readonly field with the EDITABLE hover fill, so for as long as a pointer
     * rested on one it was indistinguishable from a field you could type in â€”
     * the fill, its only cue, was being cancelled by another state.
     *
     * NO NEW TOKEN AND NO NEW VALUE: this is the same well every other field
     * owns, measured rendered against the readonly fill â€” 3.882:1 light,
     * 3.951:1 dark. Dark is the STRONGER of the two here, unlike everywhere else
     * in this file, because the dark band is a light rim and the readonly fill
     * is darker than the editable plane it normally sits over.
     *
     * DIVISION OF LABOUR AFTER THIS: the FILL separates readonly from editable,
     * the WELL separates readonly from prose. It had the first and not the
     * second. Focus behaviour is untouched â€” the caret ruling stands. */
    --fx-ctl-shadow: var(--fx-shadow-well);
    cursor: default;
}

/* Bootstrap plaintext variant: a value rendered as text but still focusable.
 * The inline padding goes through the LOCAL rather than being restated as
 * `padding-inline: 0`: section 1 already reads the local, and a literal here
 * would have to be beaten again by every size step and by the section Z
 * hardening block.
 *
 * â•â• THE CLASS IS DOUBLED â€” SAME DEFECT AS THE SIZE LADDER, SAME FIX â•â•â•â•â•â•â•â•
 *
 * FOUND 2026-08-03 by sweeping every rule in this file that redeclares an
 * fx-ctl-* local, which is the check section 1b's note asks for and which had
 * never actually been run. This was the one remaining rule that failed it.
 *
 * Written once, the selector is (0,1,0). On a `<div>` that is enough. On an
 * `<input readonly class="form-control-plaintext">` â€” which is the markup
 * Bootstrap documents and the only markup this variant is used with â€” section 1
 * ALSO matches, through its `input[type="text"]` arm at (0,1,1), and a rule takes
 * the weight of its most specific matching selector. So section 1 won all four
 * declarations and the plaintext variant did NOTHING on the element type it
 * exists for: the value rendered with the field fill, the full three-layer well
 * and 12px of inline padding, i.e. as an ordinary field. The variant's whole
 * purpose is to say "this is a value, not a control", and it was saying nothing.
 *
 * Identical in shape to the bug 1b records â€” a variant that looks correct on a
 * `<select>` or a `<div>` and is inert on the element most forms are built from â€”
 * and it takes the identical fix. Doubling lands this at (0,2,0), which clears
 * section 1's (0,1,1) without touching section 1 and without a flag.
 *
 * IT DOES NOT NEED TO CLEAR SECTION Z. That block restates the painted
 * properties by READING these same locals, so a plaintext field inside the app
 * shell resolves transparent, flat and unpadded through it rather than against
 * it. Only the LOCALS had to win, and now they do. */
.form-control-plaintext.form-control-plaintext {
    --fx-ctl-bg: transparent;
    --fx-ctl-shadow: none;
    --fx-ctl-border: 0;
    --fx-ctl-pad-x: 0;
    /* A PLAINTEXT CONTROL IS STILL A READONLY INPUT: focusable, tabbable, and
     * entitled to a focus indicator. Setting fx-ctl-shadow to none makes
     * section 2's `glow, none` invalid at computed-value time, which collapses
     * box-shadow to none â€” and with the outline transparent since 2026-08-29
     * that left it with no indicator at all. Naming the glow explicitly through
     * the opt-out hook restores it without giving the control back its well.
     * This is the ONE local nothing else in the bundle declares, so it cannot
     * be out-specified. */
    --fx-ctl-shadow-focus: var(--fx-shadow-field-focus);
}


/* â”€â”€ 3) Placeholders â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * A placeholder is a HINT, never a label. Every control must still carry a
 * visible .form-label (or an aria-label when the design truly has no room),
 * otherwise the field loses its name the moment the user starts typing.
 *
 * TWO TIERS, AND WHICH ONE DEPENDS ON WHAT THE FIELD IS FOR.
 *
 *   A FORM FIELD's placeholder is fx-color-text-subtle â€” the TERTIARY tier,
 *   which is where Linear puts it and where 00-tokens section 3.3.1 says it
 *   belongs. It is a hint the user may still need to read, so it owes AA. Now
 *   that the surface ladder is compressed, subtle clears it on every fill the
 *   placeholder can sit on:
 *       light  #58675e on #f7fbf5  5.71:1 Â· on #fbfdf9 5.85:1 Â· on #ffffff 5.97:1
 *       dark   #8b9a8f on #1b291f  5.14:1 Â· on #1f2d23 4.88:1 Â· on #233126 4.66:1
 *   The worst case is the FOCUSED dark field at 4.66:1, which still passes.
 *   (The previous pass sent placeholders to fx-color-text-muted because the OLD
 *   ladder made subtle fail on the dark well. That constraint is gone, and muted
 *   is now the BODY tier â€” a body-weight placeholder competes with the value.)
 *
 *   A SEARCH OR COMMAND FIELD's placeholder is fx-color-text-faint â€” the
 *   QUATERNARY tier, deliberately below AA. That is correct and deliberate: a
 *   search box's placeholder is a label for an empty state, not information, it
 *   is duplicated by the field's accessible name, and Linear runs it visibly
 *   quieter than a form hint so the command surface reads as empty rather than
 *   as pre-filled. Nothing a user must READ may ever be placed in this tier.
 *
 * NO FOCUS FADE, and it is not coming back. It used to drop the placeholder to
 * opacity .65 so the caret would dominate. Opacity composites the text toward
 * the fill underneath it and costs contrast in the one state the hint is
 * certain to be read in. The caret and the fill change already say which field
 * is live.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* BOTH TIERS TRAVEL THROUGH ONE LOCAL. The rule that PAINTS the placeholder is
 * written once; which grade it paints is decided by fx-ctl-placeholder on the
 * control. That is what lets a consumer say "this is a search field" by setting
 * one local, instead of shipping its own ::placeholder rule â€” 09-tabulator
 * currently carries two such copies and 03-leptonx a third, and three copies of
 * a colour decision is how the tiers drift. */
:is(.form-control, textarea, select, input)::placeholder {
    color: var(--fx-ctl-placeholder);
    opacity: 1; /* Firefox dims placeholders by default */
}

/* THE SEARCH AND COMMAND TIER, and THE TEXT CARET, which is SANCTIONED SITE 9 in
 * 00-tokens 3.9 ("the TEXT CARET in a search or command input, caret-color
 * only") and the smallest possible use of brand colour: a 1px bar, visible only
 * while the user is typing. 01-base already sets the caret on
 * input[type="search"]; it is restated here so a command palette or a filter box
 * that is not typed as search â€” the Cases and Courts dialogs both emit
 * type="text" â€” gets it too.
 *
 * THE SITE NUMBER WAS STALE UNTIL 2026-08-03 (this said "one of the six
 * sanctioned brand sites"). 3.9 has since been rewritten as a derivation with a
 * longer list beneath it; the caret's standing is unchanged, only its number.
 *
 * Both now move as LOCALS, so a consumer whose search box is a type="text"
 * input opts into the pair by redeclaring two variables and does not have to
 * name fx-color-primary itself. A layer that names the brand token directly has
 * minted an unsanctioned accent site rather than opted into this one.
 *
 * WRITTEN AS `:is()`, AND THAT IS LOAD BEARING. `:is()` takes the specificity
 * of its most specific argument, so all three arms land at (0,1,1). A plain
 * comma list would leave `.fx-search-input` at (0,1,0), which LOSES to section
 * 1's own (0,1,1) `input[type="text"]` arm â€” and a command box built on a
 * type="text" input would silently keep the form field's placeholder tier and
 * no caret. The old rules escaped this only because they contested a painted
 * property against a `:is()` list of the same weight; moving the decision into
 * a local moved the fight into section 1's arena, where the arms are heavier. */
:is(input[type="search"], .fx-search-input, .fx-command-input) {
    --fx-ctl-placeholder: var(--fx-color-text-faint);
    --fx-ctl-caret: var(--fx-color-primary);
}


/* â”€â”€ 4) Autofill neutralisation â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * Chrome paints an unremovable pale blue over autofilled fields. background
 * color is ignored, so the only reliable repaint is a very large inset shadow
 * plus text fill colour. Without this the login page reads broken in dark mode.
 * The absurd transition delay stops Chrome animating back to blue on focus.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
:is(.form-control, .form-select, textarea, select, input):-webkit-autofill,
:is(.form-control, .form-select, textarea, select, input):-webkit-autofill:hover,
:is(.form-control, .form-select, textarea, select, input):-webkit-autofill:active {
    -webkit-text-fill-color: var(--fx-ctl-fg);
    caret-color: var(--fx-ctl-fg);
    /* SHADOW ORDER IS LOAD BEARING: the first shadow in the list paints on TOP.
     * The well must therefore be listed BEFORE the 100vmax repaint, or the
     * repaint covers it and an autofilled field loses the depth that makes it
     * identifiable with no border to fall back on.
     *
     * Both halves read locals: the well from fx-ctl-shadow so a consumer that
     * retunes the depth is not undone by autofill, and the repaint from
     * fx-ctl-bg so the suppressor paints the fill the field actually has rather
     * than the fill it had before somebody restyled it. */
    box-shadow: var(--fx-ctl-shadow), 0 0 0 100vmax var(--fx-ctl-bg) inset;
    /* Deliberately NOT a duration token. This is a repaint suppressor, not an
     * animation: the value must stay absurd so Chrome never reaches the end of
     * the transition and repaints blue. Reduced motion has nothing to damp. */
    transition: background-color 100000s ease 0s, color 100000s ease 0s;
}

/* Focus keeps the glow, the well and the brighter repaint together, IN THAT
 * ORDER, and the order is the whole rule.
 *
 * â•â• THIS COMMENT USED TO SAY THE OPPOSITE, AND IT WENT STALE THE DAY THE GLOW
 * LANDED â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * It read: "the FOCUS INDICATOR itself is the outline and is not a shadow any
 * more, so there is nothing here that can be painted over". Since 2026-08-29
 * the indicator IS a shadow, and this rule is (0,3,0) â€” it out-specifies
 * section 2's (0,2,1) glow rule. So on any field outside `.lpx-content` that
 * the browser has autofilled, focus painted the well and no ring at all, with
 * the outline already transparent. That is the LOGIN FORM, which is the one
 * page where autofill is guaranteed and the one page this comment named.
 *
 * The glow is listed FIRST so it paints on top; the 100vmax fill stays LAST and
 * is `inset`, so it cannot reach outward over an outset shadow however large
 * its spread. */
:is(.form-control, .form-select, textarea, select, input):-webkit-autofill:focus {
    -webkit-text-fill-color: var(--fx-ctl-fg);
    /* fx-ctl-bg, not fx-color-field-bg-focus: section 2 has ALREADY moved the
     * local to the focus fill by the time this rule paints, so naming the token
     * again would be a second copy of the same decision â€” and a consumer that
     * gave its fields a different focus fill would find autofill was the one
     * state that ignored it. */
    box-shadow: var(--fx-shadow-field-focus), var(--fx-ctl-shadow), 0 0 0 100vmax var(--fx-ctl-bg) inset;
}


/* â”€â”€ 5) Labels, help text and the field wrapper â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * .fx-field is the vertical rhythm unit: label, control, help, error. Using it
 * is what buys the reserved message row in section 14, so validation firing
 * never pushes the rest of the form down the page.
 *
 * THE LABEL SITS ABOVE THE FIELD, 13px, WEIGHT 500, TERTIARY TIER. Linear does
 * not float or overlay labels, and it does not set them in body colour: a label
 * is chrome that names a field, and chrome lives one tier below the content it
 * names. The value inside the control is primary; the label above it is
 * fx-color-text-subtle. Weight 500 is the workhorse UI weight â€” it is what
 * makes the label read as deliberate without borrowing hierarchy from size.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* `.fx-field-label` AND `.fx-field-hint` (below) ARE ALIASES, ADDED 2026-09-28.
 * Nine screens emit them - the reception desk and its dialogs, Bookings,
 * MyVisits, the visit card, the portal's choice dialog, ServiceOfProcess,
 * ClientFunds, ChangeInitialPassword and the chat meeting scheduler - and until
 * this date NO RULE ANYWHERE MATCHED EITHER NAME. Outside a dialog the label, the
 * control and the hint therefore stayed inline and flowed onto one line: the
 * reception search box rendered narrow with its whole hint sentence beside it.
 * Inside a dialog `.frihat-dialog label` (07-surfaces, 0,1,1) still wins for a
 * <label>, so dialogs keep their rhythm; a <span> or <legend> carrying the class
 * now reads as the label it always claimed to be. Fixed here, at the base, so the
 * two names mean exactly what .fx-label and .fx-help mean on every page. */
.form-label,
.col-form-label,
.fx-label,
.fx-field-label {
    display: block;
    margin-block-end: var(--fx-space-1);
    font-weight: var(--fx-weight-medium);
    font-size: var(--fx-text-sm);
    letter-spacing: var(--fx-tracking-ui);
    line-height: var(--fx-leading-tight);
    color: var(--fx-color-text-subtle);
}

/* Required marker. The asterisk glyph carries the meaning; the colour is only
 * reinforcement, so the state survives greyscale and colour blindness. Pair it
 * with the real `required` attribute so assistive tech announces it too.
 *
 * fx-color-danger-fg, NOT fx-color-danger â€” AND THE SAME IS TRUE OF EVERY RED
 * IN THIS FILE. This is the one token trap in the danger family and it is worth
 * spelling out once, here, because every other red below points at this note.
 * 00-tokens overrides danger-fg, danger-bg and danger-border in its dark block
 * but deliberately leaves the BARE fx-color-danger alone, because that token is
 * a SOLID FILL and a fill is meant to look the same in both themes. Used as a
 * line or as text on a dark surface it therefore stays #b42318 and measures:
 *     light  #b42318 on the field fill #f7fbf5   6.28:1   PASS
 *     dark   #b42318 on the field fill #1b291f   2.31:1   FAIL
 * The -fg grade flips to p-red-300 in dark and clears both:
 *     light  #b42318 on #f7fbf5   6.28:1   PASS
 *     dark   #f2776b on #1b291f   5.51:1   PASS
 * Anything in this file that draws a red LINE or red TEXT must read the -fg
 * grade. The bare token is only correct behind fx-color-text-on-primary. */
.form-label.required::after,
.fx-label.required::after,
.fx-field-label.required::after,
.fx-field:has(> :is(input, select, textarea)[required]) > :is(.form-label, .fx-label, .fx-field-label)::after,
.fx-field.is-required > :is(.form-label, .fx-label, .fx-field-label)::after,
/* The filter bar's labels (09-tabulator, THE FILTER BAR CONTRACT): a report's
   required criterion carries the same marker as a form field's. */
.fx-filter:has(:is(input, select, textarea)[required]) > .fx-filter-label::after,
.fx-filter.is-required > .fx-filter-label::after {
    content: " *";
    font-weight: var(--fx-weight-bold);
    color: var(--fx-color-danger-fg);
}

/* The explicit opposite, for forms where most fields are mandatory. It is a
 * marker on a label that is already tertiary, so it steps down to quaternary â€”
 * the icon rule from 00-tokens 2.2 applied to a word. */
.fx-label-optional {
    margin-inline-start: var(--fx-space-1);
    font-size: var(--fx-text-2xs);
    font-weight: var(--fx-weight-regular);
    color: var(--fx-color-text-faint);
}

/* Help text is prose the user is expected to READ, so it sits on the sm step
 * (13px), not on a caption step. 2xs is contractually micro labels only.
 * TERTIARY, not the body tier: it is metadata attached to a field, and putting
 * it at fx-color-text-muted would make the hint compete with the value. */
.form-text,
.fx-help,
.fx-field-hint {
    display: block;
    margin-block-start: var(--fx-space-1);
    font-size: var(--fx-text-sm);
    line-height: var(--fx-leading-normal);
    color: var(--fx-color-text-subtle);
}

.fx-field {
    display: block;
    margin-block-end: var(--fx-space-4);
    min-inline-size: 0;
}

.fx-field > :is(.form-control, .form-select, textarea, select, input) {
    margin-block-end: 0;
}

/* Inline field: label beside the control, for dense filter rows. Wraps rather
 * than overflowing once the label plus the control no longer share a line. */
.fx-field-inline {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fx-space-2);
    min-inline-size: 0;
}

.fx-field-inline > :is(.form-label, .fx-label) {
    margin-block-end: 0;
    white-space: nowrap;
}


/* â”€â”€ 6) Responsive form grid â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * One column on a phone, two from the tablet width, three on a wide desktop.
 * The auto-fit plus min(basis, 100%) pattern does the collapsing without a
 * media query, and the min() guard is what stops a 390px phone from producing
 * a horizontal page scrollbar: the track can never demand more than the
 * container gives it. The explicit breakpoints below only pin the intended
 * column counts so a half width browser window behaves predictably.
 *
 * Sanity checked at 390x844, 1024x768, 1366x768, 1440x900, 1920x1080,
 * 2560x1440 and 3840x2160. No fixed pixel width participates in the layout.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* DENSITY: THE AIR GOES BETWEEN THE GROUPS, NOT INSIDE THEM.
 * A field group is tight â€” a 13px label sitting one 4px step above its control,
 * help text one step under it â€” and the generosity is spent here, on the gap
 * between one group and the next. The row gap is therefore fx-space-5 (20 â†’ 24px
 * fluid) rather than the 8px it used to be, which is what makes a dense column
 * of compact controls read as composed rather than as crammed. */
.fx-form-grid {
    --fx-form-basis: 17rem;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(var(--fx-form-basis), 100%), 1fr));
    gap: var(--fx-space-5) var(--fx-gutter);
    align-items: start;
    inline-size: 100%;
    min-inline-size: 0;
}

/* Inside a grid the ROW GAP is the rhythm, so a field must not also carry its
 * own bottom margin â€” the two would stack and the form would breathe unevenly
 * between a grid row and a standalone field. */
.fx-form-grid .fx-field {
    margin-block-end: 0;
}

/* Below the tablet width the grid is deliberately a single column: two columns
 * of Arabic labels under 768px are unreadable, not merely tight. */
@media (max-width: 767.98px) {
    .fx-form-grid,
    .fx-form-grid-3 {
        grid-template-columns: 1fr;
    }
}

/* Three column density is only offered once there is genuine room for it. */
@media (min-width: 1400px) {
    .fx-form-grid-3 {
        --fx-form-basis: 13rem;
    }
}

@media (max-width: 1399.98px) {
    .fx-form-grid-3 {
        --fx-form-basis: 17rem;
    }
}

/* Full width row inside the grid, for textareas and long legal titles. */
.fx-form-grid > .fx-field-full,
.fx-form-grid > .fx-col-full,
.fx-form-grid > .fx-span-all {
    grid-column: 1 / -1;
}

/* Ultrawide cap. A single line text field stretched across a 4K monitor is
 * unreadable and looks unfinished, so the CONTROL is capped by the shared
 * measure token while the grid itself keeps filling the page. Using the token
 * rather than a local ch value keeps every capped column in the design system
 * on one number. */
@media (min-width: 1800px) {
    .fx-field > :is(.form-control, .form-select, select, input, textarea),
    .fx-form-grid > * > :is(.form-control, .form-select, select, input, textarea) {
        max-inline-size: var(--fx-measure);
    }

    .fx-form-grid {
        --fx-form-basis: 20rem;
    }
}

/* ── 6b) The short task form: stack, paired fields, actions, disabled reason ──
 * Added 2026-09-28 for the forms that ask for ONE thing - invite a client, ask
 * for an appointment, register an arrival - and first used on /Reception,
 * /Reception/OnlineMeetings and /Portal. All four are NEW, OPT-IN classes: no
 * existing selector changes meaning, so no other page moves.
 *
 * WHY A STACK AND NOT THE GRID ABOVE. `.fx-form-grid` auto-fits 17rem tracks,
 * which is right for a twenty field record editor and wrong for a four field
 * task: the client select, the day, the time and the subject landed in columns
 * of equal width, so a date box was as wide as a name and a time box as wide as
 * a sentence. A task form reads top to bottom in one column, capped at the
 * shared measure so it never stretches across a wide desk monitor.
 * ────────────────────────────────────────────────────────────────────────── */
.fx-form-stack {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--fx-space-4);
    inline-size: 100%;
    max-inline-size: 40rem;
    min-inline-size: 0;
}

/* The stack's gap is the rhythm, exactly as the grid's is above. */
.fx-form-stack .fx-field {
    margin-block-end: 0;
}

/* FIELDS THAT BELONG TOGETHER SIT ON ONE LINE AT THEIR OWN WIDTH. A day and a
 * time are one answer to "when", so they share a row; each keeps a width that
 * fits its content (dd/mm/yyyy, hh:mm plus the picker affordance) instead of
 * stretching to whatever the column offers. Flex, not grid, so the pair wraps
 * on its own when the column is narrower than both. */
.fx-field-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--fx-space-4) var(--fx-gutter);
    min-inline-size: 0;
}

.fx-field-row > .fx-field {
    flex: 1 1 12rem;
    margin-block-end: 0;
    min-inline-size: 0;
}

.fx-field-row > .fx-field-date {
    flex: 0 1 12rem;
}

.fx-field-row > .fx-field-time {
    flex: 0 1 9rem;
}

/* On a phone the fixed widths give way: each field takes the whole line it is
 * on, so the pair stacks rather than leaving two narrow islands. */
@media (max-width: 767.98px) {
    .fx-field-row > :is(.fx-field-date, .fx-field-time) {
        flex: 1 1 10rem;
    }
}

/* THE PRIMARY ACTION SITS AGAINST THE FIELDS IT SUBMITS, at the start edge
 * (the right in Arabic, the left in English, from the writing direction with no
 * RTL rule), never floated to the far end of a wide card. */
.fx-form-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fx-space-2) var(--fx-space-3);
    margin-block-start: var(--fx-space-4);
    min-inline-size: 0;
}

/* A DISABLED BUTTON ALWAYS SAYS WHY, ON SCREEN. A tooltip is invisible to touch
 * and to anyone who does not hover, so the reason is a visible sentence beside
 * the button, referenced from it through aria-describedby. Tertiary text tier,
 * exactly as field help: it explains a control, it does not compete with it.
 * Empty, it takes no space. */
.fx-action-reason {
    flex: 1 1 14rem;
    min-inline-size: 0;
    font-size: var(--fx-text-sm);
    line-height: var(--fx-leading-normal);
    color: var(--fx-color-text-subtle);
}

.fx-action-reason:empty {
    display: none;
}

/* A titled block inside a long form. */
.fx-fieldset {
    margin-block-end: var(--fx-space-5);
    padding: 0;
    border: 0;
}

/* NO TRACKING, NO UPPERCASING â€” both were Latin habits applied to an Arabic
 * first interface, and both actively damage it.
 *
 * fx-tracking-wide is +0.04em. The Arabic guard in 00-tokens.css zeroes the
 * NEGATIVE ramp but not this one, so the value survives into Arabic â€” and
 * Arabic is a cursive, joined script where any letter-spacing, positive or
 * negative, pulls the glyphs apart at their joins. text-transform: uppercase is
 * simply inert in Arabic, so it bought nothing here and quietly shouted at the
 * English half of a bilingual deployment.
 *
 * The hierarchy this legend needs is carried by WEIGHT and by the TERTIARY text
 * tier instead â€” which is the house rule anyway, and costs no size step. */
.fx-fieldset > legend,
.fx-fieldset-title {
    display: block;
    inline-size: 100%;
    margin-block-end: var(--fx-space-3);
    padding-block-end: var(--fx-space-2);
    font-size: var(--fx-text-sm);
    font-weight: var(--fx-weight-semibold);
    letter-spacing: var(--fx-tracking-ui);
    color: var(--fx-color-text-subtle);
    /* An in-flow separator inside a surface whose colour is known, so it comes
     * from the OPAQUE divider family, not the translucent border family. It is
     * expressed as a shadow so nothing in this file paints a resting border. */
    box-shadow: inset 0 calc(var(--fx-border-width) * -1) 0 var(--fx-color-divider);
}


/* â”€â”€ 7) Select â€” the trigger and its popup â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * 7.0 THE NATIVE <select>. Bootstrap supplies the caret image for .form-select
 * and ships an RTL flipped build, so the caret side is handled upstream. We only
 * retune colour, spacing and the open state. A bare <select> keeps its native
 * caret on purpose: the platform renders it on the correct side in RTL for free
 * and it needs no image, which keeps this file colour literal free.
 *
 * THE NATIVE POPUP IS OS DRAWN ON A LEGACY ENGINE AND CANNOT BE THEMED THERE â€”
 * no author rule reaches inside it. The only lever is color-scheme, which
 * section 9 sets on the control itself so the platform picks the matching light
 * or dark list rendering. That is what stops a white option list dropping out of
 * a dark application. The option and optgroup rules below are honoured only by
 * the engines that expose them, and on a legacy engine they are a bonus rather
 * than the mechanism.
 *
 * â•â• THAT LIMIT IS NOW A FALLBACK, NOT THE CEILING. READ 7.0a. â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * This paragraph used to say that a native select can never rotate a chevron and
 * can never host our own artwork, because on .form-select the caret is a
 * background-image that cannot be rotated independently of its element and a
 * <select> was a replaced element able to host neither a ::after nor any child.
 * That was true of `appearance: none`, which only ever styled the CLOSED
 * control, and it is the reason the client saw a stock operating system window
 * with no styling and no motion behind every ABP, DataTables and LeptonX select
 * on the platform.
 *
 * `appearance: base-select` retires it. In an engine that supports it a <select>
 * stops being a replaced element: the trigger becomes a real flex container with
 * a ::picker-icon we can mask and rotate, and the option list becomes
 * ::picker(select) â€” a genuine, styleable, ANIMATABLE element in the top layer.
 * Section 7.0a builds exactly that, inside an @supports gate, so an engine
 * without it keeps every rule above untouched. The custom combobox of 7.1 is
 * still the right answer where the markup needs icons, descriptions or a
 * two-line row, and 7.0a is deliberately styled to be indistinguishable from it.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.form-select {
    padding-inline-end: calc(var(--fx-ctl-pad-x) + var(--fx-icon-md));
    cursor: pointer;
}

/* A bare <select> keeps the platform caret, which is drawn on the correct side
 * in RTL for free. `border: 0` from section 1 still applies and is what stops
 * appearance: auto from bringing the user agent's hairline back with the caret â€”
 * the well must survive the native chrome, not be replaced by it. */
select:not(.form-select) {
    appearance: auto;
    /* Through the local, matching what section 7.0a does to the base-select
     * trigger. It used to be a flat fx-space-2, which meant a select on the xs
     * or lg step kept the 8px trailing gutter of the default step and its caret
     * sat at a different inset from every other field in the same row. */
    padding-inline-end: var(--fx-ctl-pad-x);
    cursor: pointer;
}

/* OPEN. Progressive enhancement: :open on a <select> is recent, so where it is
 * unsupported the control simply keeps its focus treatment, which it already has
 * because opening a select focuses it. Where it IS supported the trigger holds
 * the brightened fill for as long as the list is down, so the field visibly
 * stays the active one while the OS popup covers the page. */
:is(select, .form-select):open {
    --fx-ctl-bg: var(--fx-color-field-bg-focus);
}

select[multiple],
select[size]:not([size="1"]) {
    padding-inline-end: var(--fx-ctl-pad-x);
    background-image: none;
    min-block-size: auto;
}

/* Option rows follow the OVERLAY surface, not a flat white, so the popup is not
 * a white rectangle in dark mode on platforms that honour author styling.
 * fx-color-surface-raised resolves to level 3 in light and level 2 in dark,
 * which is the same deliberate asymmetry the custom popup uses in 7.2. */
:is(select, .form-select) option {
    color: var(--fx-color-text-muted);
    background-color: var(--fx-color-surface-raised);
}

:is(select, .form-select) optgroup {
    color: var(--fx-color-text-subtle);
    background-color: var(--fx-color-surface-raised);
    font-weight: var(--fx-weight-semibold);
}


/* â”€â”€ 7.0a) THE CSS CUSTOMIZABLE SELECT â€” appearance: base-select â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * THE DEFECT THIS FIXES, in the client's own words from a running build:
 * "all drop down window looks stupidâ€¦ no motions no style at all." That was an
 * accurate report of a platform limit, not of a missing rule. A native select's
 * option list is drawn by the OPERATING SYSTEM, outside the page, and no author
 * stylesheet reaches inside it. `appearance: none` styles only the CLOSED
 * control, which is why every ABP, DataTables and LeptonX select on the platform
 * â€” the DataTables page length control, the Tabulator page size control, every
 * .form-select in a module dialog â€” opened a stock system window with none of
 * this design system in it and no transition of any kind.
 *
 * `appearance: base-select` is the fix, and it is a genuinely different model
 * rather than a better hack: the select stops being a replaced element. The
 * trigger becomes a real flex container holding a `selectedcontent` and a
 * `::picker-icon`, and the list becomes `::picker(select)` â€” a real element in
 * the TOP LAYER that takes our fill, our radius, our shadow stack and, because
 * it is a real element, our motion.
 *
 * â•â• THIS IS PROGRESSIVE ENHANCEMENT, AND THE GATE IS LOAD BEARING â•â•â•â•â•â•â•â•â•â•
 *
 * Everything below sits inside @supports (appearance: base-select). Gecko and
 * WebKit do not ship it yet, drop the whole block, and keep exactly the styled
 * trigger plus OS list they render today â€” section 7.0 above is untouched and
 * remains the fallback. Nothing here is a prerequisite for anything there.
 *
 * The gate is also what makes the ::picker and ::picker-icon selectors SAFE. An
 * unrecognised pseudo-element invalidates the complex selector that contains it,
 * and one invalid complex selector invalidates an entire selector LIST. So no
 * ::picker selector may ever be added to one of the shared lists elsewhere in
 * this file â€” sections 16.3, 16.4 and 17 would each lose every control they
 * style in Firefox the moment somebody appended `::picker(select)` to them. The
 * contrast, forced-colours and print counterparts for the picker are therefore
 * declared HERE, inside the gate, as rules of their own. Keep it that way.
 *
 * â•â• IT IS DELIBERATELY THE SAME OBJECT AS .fx-select-popup (7.2) â•â•â•â•â•â•â•â•â•â•â•
 *
 * Same surface pair, same 4px gutter, same 10px container radius around 6px
 * rows, same 32px row height, same neutral highlight, same 80ms in / 60ms out.
 * A user must not be able to tell a native select from our own combobox, and a
 * reviewer must not have to hold two answers for "what does a menu look like".
 *
 * NO BRAND ANYWHERE IN THE PICKER. Under the current contract identity and
 * position are brand; INTERACTION is neutral. A highlighted option and a checked
 * option are both interaction, so both take a neutral wash â€” fx-color-hover and
 * fx-color-active. The only brand left in this file is the text caret of
 * section 3 and the checked fill of section 12.
 *
 * RTL. Logical properties throughout, and the picker needs no mirror of its own:
 * it is anchored to its trigger by the user agent, so it aligns to whichever
 * edge the trigger's inline start is on. The one transform is a block-axis
 * scale about a block-axis origin, which is direction neutral.
 *
 * THE MULTI SELECT GUARD. `select:not([multiple], [size]:not([size="1"]))`
 * appears on every rule that changes layout. A <select multiple> and a sized
 * list box are NOT drop-downs, get no picker, and would be visibly broken by a
 * trigger rule that turns them into a single flex row. Section 7.0 already
 * carries their own rules and they must keep them. The guard also buys the
 * specificity these rules need: it computes to (0,2,1), which beats both
 * `.form-select` (0,1,0) and section 7.0's `select:not(.form-select)` (0,1,1),
 * so `appearance: auto` and the Bootstrap caret padding are cleanly superseded
 * rather than fought.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
@supports (appearance: base-select) {

    /* THE OPT IN. Both halves of it: the control and its picker. Without the
     * second selector the list stays OS drawn and none of the rules below have
     * anything to style. */
    select:not([multiple], [size]:not([size="1"])),
    ::picker(select) {
        appearance: base-select;
    }

    /* 7.0a.1 THE TRIGGER â€” the field geometry of section 1, unchanged.
     *
     * Nothing here re-declares the well, the radius, the height or the fills:
     * they arrive from section 1 through the --fx-ctl-* locals and MUST keep
     * arriving from there, because fx-shadow-well is the SC 1.4.11 carrier
     * measured at 4.13:1 light and 4.34:1 dark. This rule only undoes the three
     * things the base appearance and Bootstrap hand back: the Bootstrap caret
     * image, the horizontal padding reserved for that image, and the default
     * alignment of what is now a flex container. */
    select:not([multiple], [size]:not([size="1"])) {
        /* INLINE-flex, and the distinction is the bug section 1a exists to stop.
         * `display: flex` is BLOCK level, so it would make every bare select on
         * the platform fill its container â€” which is precisely how the Tabulator
         * footer page size control ended up wrapping onto its own row. Full
         * width remains a FORM LAYOUT decision granted by section 1a, never a
         * side effect of a control becoming a flex container. */
        /* THE DOUBLE BOX, AND WHY padding-block MUST BE ZERO HERE.
         *
         * Measured on the running app, not reasoned about. On Identity/Roles the
         * DataTables page length control rendered 45.5px tall against a 28px
         * min-block-size, with the value and the chevron stacked. Probing it in
         * the live document isolated the cause exactly:
         *
         *     as shipped                                 45.5px
         *     padding: 0                                 33.5px
         *     padding: 0 + inline-flex + align-items     28.0px   â† the target
         *
         * Every select on this platform arrives from ABP, DataTables or LeptonX
         * as a plain `<select>` with no inner button, so the browser GENERATES
         * the button and selectedcontent pair in shadow DOM. That generated
         * button carries its own box. Section 1's padding-block is then applied
         * to the select AROUND it, and the two stack: our padding, then the
         * button's, then the line box. The control cannot honour a height it is
         * being padded past.
         *
         * So the vertical rhythm is handed to min-block-size and align-items
         * instead of to padding. The block padding goes to zero, the inline
         * padding stays because it is the text gutter and nothing else supplies
         * it, and the flex row is what lets the generated button centre inside
         * the control's own height rather than dictate it.
         *
         * This is also why the height is correct at every size: min-block-size
         * reads --fx-ctl-h, so the sm and lg variants resolve their own step
         * without this rule knowing they exist. Verified at 28px for
         * .form-select-sm, which is --fx-control-h-sm exactly. */
        /* block-size, NOT min-block-size, and NOT flex centring.
         *
         * Probed live: with the padding removed the control still measured
         * 33.5px against a 28px minimum, and `display` would not move off
         * inline-block no matter what an author stylesheet asked for. The
         * generated button is laid out by the user agent and carries its own
         * box; a MINIMUM height cannot claw back space something else is adding,
         * and the flex centring that would have absorbed it needs a display
         * value we are not permitted to set on a base appearance select.
         *
         * So the height is stated outright. It reads --fx-ctl-h, which is the
         * same local the sm and lg modifiers redeclare, so every size still
         * resolves its own step from one declaration â€” measured at exactly 28px
         * for .form-select-sm. The flex pair below is kept for the case where a
         * page authors the inner markup itself, where it does apply and is
         * correct; it is simply inert for the markup ABP and DataTables emit. */
        block-size: var(--fx-ctl-h);
        display: inline-flex;
        align-items: center;
        padding-block: 0;
        /* start, never left: the value hugs the inline start in both directions,
         * exactly as .fx-select-trigger does in 7.1. */
        text-align: start;
        /* The Bootstrap caret is a background-image and there is a real
         * ::picker-icon element now. Two carets is worse than none. */
        background-image: none;
        /* .form-select reserves an icon's width of trailing padding for that
         * image. The icon is a flex item now and reserves its own room, so the
         * field goes back to symmetric control padding. Read from the local, so
         * the sm and lg variants still resolve their own step. */
        padding-inline-end: var(--fx-ctl-pad-x);
        /* Belt and braces for the auto-generated case. Where the page writes the
         * markup out â€” <select><button><selectedcontent></selectedcontent> â€” the
         * rule below truncates the value itself. Where it does not, the browser
         * generates that pair for us and it may not be reachable from an author
         * stylesheet, so the clip is stated on the control as well and a long
         * option label can never paint past the field. It cannot clip the picker:
         * that lives in the top layer and no ancestor's overflow reaches it. */
        overflow: hidden;
        cursor: pointer;
    }

    /* THE CLOSED VALUE. Owns the row and truncates; the icon never shrinks â€”
     * the same division of labour, and the same min-inline-size: 0 trick, that
     * .fx-select-trigger > .value uses in 7.1. Without min-inline-size: 0 a
     * flex item's min-content width wins and a long option pushes the chevron
     * out of the control. */
    select:not([multiple], [size]:not([size="1"])) selectedcontent,
    selectedcontent {
        flex: 1;
        min-inline-size: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        text-align: start;
        color: var(--fx-color-text);
    }

    /* 7.0a.2 THE CHEVRON. Our own artwork at last â€” the identical mask, the
     * identical quaternary tier and the identical rotation that
     * .fx-select-chevron carries in 7.1, on a NATIVE select.
     *
     * fx-dur-quick (120ms) is the shared chevron step: the tree disclosure in
     * 06-navigation and the combobox chevron in 7.1 both rotate on it, so the
     * three cannot drift. content: "" clears the user agent's own triangle so
     * the mask is the only thing painted. */
    select::picker-icon {
        content: "";
        flex-shrink: 0;
        inline-size: var(--fx-icon-md);
        block-size: var(--fx-icon-md);
        color: var(--fx-color-text-faint);
        background-color: currentColor;
        -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 6 8 10.5 12.5 6l-1.1-1.1L8 8.3 4.6 4.9z'/%3E%3C/svg%3E");
        mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 6 8 10.5 12.5 6l-1.1-1.1L8 8.3 4.6 4.9z'/%3E%3C/svg%3E");
        -webkit-mask-repeat: no-repeat;
        mask-repeat: no-repeat;
        -webkit-mask-size: contain;
        mask-size: contain;
        transition: transform var(--fx-dur-quick) var(--fx-ease-standard);
    }

    /* Rotation is symmetric about the block axis, so it needs no RTL mirror. */
    select:open::picker-icon {
        transform: rotate(180deg);
    }

    /* 7.0a.3 THE PICKER.
     *
     * SURFACE. fx-color-surface-raised, which resolves to level 3 in light and
     * level 2 in dark. That asymmetry is structural rather than an inversion:
     * in light "raised" means whiter than the tinted page, in dark it means
     * closer to the light than the near black page. Reading the one token keeps
     * the pair in 00-tokens where it belongs, and keeps this picker and the
     * .fx-select-popup of 7.2 on a single source of truth.
     *
     * THE EDGE is the TRANSLUCENT border family, not the opaque divider family:
     * a floating surface can land on anything. It is allowed to be nearly
     * invisible â€” a container edge identifies nothing, and this file's SC 1.4.11
     * obligation is discharged by the trigger's well.
     *
     * THE GUTTER IS WHAT MAKES A MENU LOOK BUILT. 4px of fx-popover-pad inside
     * the container, around rows that carry a 6px radius, so the first and last
     * row float inside the panel instead of touching its wall.
     *
     * THE SHADOW IS BOTH LAYERS. fx-shadow-stack is the physical edge and
     * fx-shadow-float-lg is the ambient cast; a floating panel that carries only
     * the cast reads as a printed rectangle sliding over the page.
     *
     * WIDTH. The user agent already anchors the picker and defaults its
     * min-inline-size to the trigger's own inline size, which is the behaviour
     * we want; all this adds is the platform floor so a three character select
     * does not open a 60px menu. If anchor-size() is ever unavailable the
     * declaration is simply invalid and the user agent default survives, which
     * is a safe failure rather than a collapsed popup.
     *
     * The margin, border and background the user agent supplies are all killed
     * outright: background is written as the shorthand on purpose, so a UA
     * background-image cannot survive under our fill. */
    select::picker(select) {
        box-sizing: border-box;
        min-inline-size: max(anchor-size(self-inline), var(--fx-popover-min-w));
        max-inline-size: 100vi;
        max-block-size: min(20rem, 60svh);
        overflow-y: auto;
        overscroll-behavior: contain;
        margin: 0;
        padding: var(--fx-popover-pad);
        font-family: inherit;
        color: var(--fx-color-text-muted);
        background: var(--fx-color-surface-raised);
        border: var(--fx-border-width) solid var(--fx-color-border);
        border-radius: var(--fx-radius-lg);
        box-shadow: var(--fx-shadow-stack), var(--fx-shadow-float-lg);
    }

    /* 7.0a.4 MOTION â€” the answer to "no motions".
     *
     * THE PICKER LIVES IN THE TOP LAYER, which is why this cannot be an ordinary
     * two state transition. Opening flips `display` away from none AND adds the
     * element to the overlay, and both of those are DISCRETE properties: without
     * `allow-discrete` on each, the browser applies them instantly at frame zero
     * and there is nothing left for opacity and transform to animate against â€”
     * the popup blinks, which is exactly the "no motion" the client reported.
     * `@starting-style` supplies the before-open frame, because an element that
     * has just been rendered for the first time has no previous style to
     * transition FROM.
     *
     * WHICH RULE OWNS WHICH DIRECTION. A transition is read from the DESTINATION
     * state, so the closed rule times the EXIT and the :open rule times the
     * ENTRANCE. That is why the two differ, and it is not a copy paste slip:
     *     entrance  fx-dur-enter (80ms)  fx-ease-standard
     *     exit      fx-dur-exit  (60ms)  fx-ease-in-quad
     * THE EXIT IS FASTER THAN THE ENTRANCE ON PURPOSE. A menu that takes as long
     * to leave as it took to arrive feels like it is arguing with the click that
     * dismissed it. Identical numbers and curves to .fx-select-popup in 7.2.
     *
     * transform-origin is anchored toward the trigger, so the panel grows out of
     * the field rather than out of thin air. It is a block-axis keyword pair, so
     * it is direction neutral and needs no RTL mirror. When the user agent flips
     * the picker above a trigger near the viewport floor the origin is nominally
     * the wrong end of a 4 percent scale â€” under 6px of travel, which is not
     * worth a script to correct.
     *
     * Wrapped in prefers-reduced-motion: no-preference, so a vestibular user
     * gets the identical panel, fills and states arriving instantly. Note that
     * the CLOSED opacity and transform live inside the gate too: leaving them
     * outside would hide the picker outright for that user. */
    @media (prefers-reduced-motion: no-preference) {
        select::picker(select) {
            opacity: 0;
            transform: scale(var(--fx-enter-scale));
            transform-origin: center top;
            transition:
                opacity var(--fx-dur-exit) var(--fx-ease-in-quad),
                transform var(--fx-dur-exit) var(--fx-ease-in-quad),
                display var(--fx-dur-exit) allow-discrete,
                overlay var(--fx-dur-exit) allow-discrete;
        }

        select:open::picker(select) {
            opacity: 1;
            transform: scale(1);
            transition:
                opacity var(--fx-dur-enter) var(--fx-ease-standard),
                transform var(--fx-dur-enter) var(--fx-ease-standard),
                display var(--fx-dur-enter) allow-discrete,
                overlay var(--fx-dur-enter) allow-discrete;
        }

        @starting-style {
            select:open::picker(select) {
                opacity: 0;
                transform: scale(var(--fx-enter-scale));
            }
        }
    }

    /* 7.0a.5 THE OPTION ROW. Every number is the one .fx-select-item uses in
     * 7.3, so a native list and our combobox list are the same object:
     *     height   fx-menu-item-h      32px fine, 44px coarse
     *     padding  fx-menu-item-pad-x  14px fine, 18px coarse
     *     radius   fx-radius-item      6px, floating inside the 4px gutter
     *     gap      fx-control-gap-sm   8px between the checkmark and the label
     *     type     fx-text-sm          13px, regular weight
     * Both height and padding come off the token tier, so a coarse pointer grows
     * the rows to a 44px touch target with no media query written here.
     *
     * REST IS THE SECONDARY TEXT TIER. An unhighlighted row is quieter than the
     * value in the field above it, and promotes to primary the moment it is
     * hovered or walked onto â€” the same promotion the whole menu vocabulary of
     * this platform uses. */
    select:not([multiple], [size]:not([size="1"])) option {
        display: flex;
        align-items: center;
        gap: var(--fx-control-gap-sm);
        box-sizing: border-box;
        min-block-size: var(--fx-menu-item-h);
        padding-block: 0;
        padding-inline: var(--fx-menu-item-pad-x);
        overflow: hidden;
        font-size: var(--fx-text-sm);
        font-weight: var(--fx-weight-regular);
        letter-spacing: var(--fx-tracking-ui);
        line-height: var(--fx-leading-snug);
        text-align: start;
        white-space: nowrap;
        color: var(--fx-color-text-muted);
        background-color: transparent;
        border-radius: var(--fx-radius-item);
        cursor: pointer;
        transition:
            color var(--fx-dur-instant) var(--fx-ease-standard),
            background-color var(--fx-dur-instant) var(--fx-ease-standard);
    }

    @media (any-hover: hover) {
        select:not([multiple], [size]:not([size="1"])) option:hover:not(:disabled) {
            color: var(--fx-color-text);
            background-color: var(--fx-color-hover);
        }
    }

    /* THE ROVING FOCUS EXCEPTION, and the only one this file grants outside
     * section 7.3. A ring inside a picker traces a second rounded rectangle 2px
     * outside a row that sits in a container only 4px wider than it is, and it
     * reads as a rendering fault. The ring stays on the TRIGGER, which is what
     * the user tabbed to; the row says where it is with a wash. See 2.1. */
    select:not([multiple], [size]:not([size="1"])) option:focus,
    select:not([multiple], [size]:not([size="1"])) option:focus-visible {
        outline: none;
        color: var(--fx-color-text);
        background-color: var(--fx-color-hover);
    }

    /* CHECKED IS INTERACTION, SO IT IS NEUTRAL. fx-color-active is the 8 percent
     * wash, one step above the 5 percent hover, which is exactly how 7.3 tells
     * "the selected one" from "the one under the pointer". No brand here. */
    select:not([multiple], [size]:not([size="1"])) option:checked {
        color: var(--fx-color-text);
        background-color: var(--fx-color-active);
    }

    select:not([multiple], [size]:not([size="1"])) option:disabled {
        color: var(--fx-color-disabled-fg);
        background-color: transparent;
        cursor: not-allowed;
    }

    /* 7.0a.6 THE CHECKMARK â€” SHOWN, AND ITS SLOT IS ALWAYS RESERVED.
     *
     * The alternative was hiding it, and reserving the slot is what makes that
     * the wrong call: if the glyph only occupied space when a row was checked,
     * every label in the list would shift sideways by 24px the moment the user
     * changed the selection, and a list of court names would appear to move
     * under the pointer. So the box is always laid out and only its VISIBILITY
     * changes â€” visibility, not display, precisely because visibility keeps the
     * layout. The mask is the same tick the valid state uses in section 14, so
     * no new artwork and no colour literal enters the file. */
    option::checkmark {
        content: "";
        flex: 0 0 auto;
        order: -1;
        inline-size: var(--fx-icon-md);
        block-size: var(--fx-icon-md);
        visibility: hidden;
        background-color: currentColor;
        -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M13.6 4.2 6.3 11.5 2.4 7.6l1.4-1.4 2.5 2.5 5.9-5.9z'/%3E%3C/svg%3E");
        mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M13.6 4.2 6.3 11.5 2.4 7.6l1.4-1.4 2.5 2.5 5.9-5.9z'/%3E%3C/svg%3E");
        -webkit-mask-repeat: no-repeat;
        mask-repeat: no-repeat;
        -webkit-mask-size: contain;
        mask-size: contain;
    }

    option:checked::checkmark {
        visibility: visible;
    }

    /* 7.0a.7 GROUPS. 12px at weight 500 on the tertiary tier, in a 30px slot â€”
     * the same section label the rest of the platform draws, and one step
     * quieter than the 13px regular rows underneath it, so the heading reads as
     * chrome rather than as an unselectable option.
     *
     * <optgroup><legend>â€¦</legend> is the markup the customizable select expects
     * and the only shape that can be given the 30px slot. A legacy `label`
     * attribute still renders, and still picks up the type and the colour from
     * the optgroup rule, but the user agent owns its box. NOTE for the next
     * editor: do NOT add a speculative `optgroup::label` to this selector list.
     * There is no such pseudo-element, and an unknown pseudo-element would
     * invalidate the entire rule rather than just that one selector. */
    select:not([multiple], [size]:not([size="1"])) optgroup {
        display: block;
        padding: 0;
        font-size: var(--fx-text-xs);
        font-weight: var(--fx-weight-medium);
        color: var(--fx-color-text-subtle);
        background-color: transparent;
    }

    select:not([multiple], [size]:not([size="1"])) optgroup > legend {
        display: flex;
        align-items: center;
        min-block-size: var(--fx-section-label-h);
        padding-block: 0;
        padding-inline: var(--fx-menu-item-pad-x);
        font-size: var(--fx-text-xs);
        font-weight: var(--fx-weight-medium);
        letter-spacing: var(--fx-tracking-ui);
        color: var(--fx-color-text-subtle);
    }

    /* 7.0a.8 The four preference branches, declared HERE rather than appended
     * to the shared lists in sections 16 and 17 â€” see the note at the head of
     * this section for why that separation is not optional. */

    /* Reduced motion. The picker's own entrance and exit are already gated on
     * no-preference and simply do not exist in this branch. What is left is the
     * chevron, which is declared unconditionally because the ROTATION carries
     * the open state and must survive: it is damped to instant here, the same
     * answer section 16.2 gives .fx-select-chevron. */
    @media (prefers-reduced-motion: reduce) {
        select::picker-icon {
            transition-duration: var(--fx-dur-instant);
        }
    }

    /* More contrast: the picker regains a full strength edge, drawn inside its
     * own box so nothing reflows, and the chevron leaves the quaternary tier. */
    @media (prefers-contrast: more) {
        select::picker(select) {
            outline: var(--fx-border-width-strong) solid var(--fx-color-text);
            outline-offset: calc(var(--fx-border-width-strong) * -1);
        }

        select::picker-icon {
            color: var(--fx-color-text);
        }
    }

    /* Forced colours: every author colour is discarded and box-shadow is dropped
     * entirely, so the panel would otherwise be an unbordered void. The border
     * is the only thing that survives, and the highlighted row has to opt out of
     * the forced palette to keep its pairing legible. */
    @media (forced-colors: active) {
        select::picker(select) {
            border: var(--fx-border-width) solid ButtonBorder;
        }

        select:not([multiple], [size]:not([size="1"])) option:checked,
        select:not([multiple], [size]:not([size="1"])) option:focus {
            background-color: Highlight;
            color: HighlightText;
            forced-color-adjust: none;
        }
    }

    /* A picker is transient chrome and has no meaning on paper. Section 17 hides
     * .fx-select-popup and .fx-select-chevron for the same reason; the picker
     * cannot join that list without risking it in Firefox. */
    @media print {
        select::picker(select),
        select::picker-icon {
            display: none;
        }
    }
}


/* 7.1 THE CUSTOM SELECT TRIGGER.
 *
 * Markup contract, so the popup and the trigger cannot drift apart:
 *
 *   <div class="fx-select">
 *     <button class="fx-select-trigger" aria-haspopup="listbox" aria-expanded>
 *       <span class="value">â€¦</span>          or  <span class="placeholder">â€¦</span>
 *       <span class="fx-select-chevron" aria-hidden="true"></span>
 *     </button>
 *     <div class="fx-select-popup" role="listbox">
 *       <div class="fx-select-item" role="option">â€¦</div>
 *       <div class="fx-select-separator" role="separator"></div>
 *     </div>
 *   </div>
 *
 * The trigger is a text control by geometry and reads the same locals, so a
 * combobox and an <input> beside it are the same object at the same height with
 * the same well. It is a <button>, so it must NOT take fx-radius-control: the
 * pill belongs to things that are buttons by ROLE, and this one is a field.
 *
 * THE VALUE OWNS THE ROW AND TRUNCATES; THE CHEVRON NEVER SHRINKS. min-inline-size
 * 0 is what makes text-overflow work at all inside a flex item â€” without it the
 * value's min-content width wins and the chevron is pushed out of the box. */
.fx-select {
    position: relative;
    display: block;
    inline-size: 100%;
    min-inline-size: 0;
}

/* THE TRIGGER IS A <button>, SO IT IS NOT IN SECTION 1's SELECTOR LIST AND
 * CARRIES NO LOCALS OF ITS OWN. It therefore declares the WHOLE fx-ctl-* set
 * rather than the five it used to, and then reads every one of them. The three
 * it was missing â€” pad-y, fg and the type pair â€” were restated as fx-space-2,
 * fx-color-text, `inherit` and fx-leading-snug, which meant a page could put
 * `.fx-control-sm` on a combobox and get a 28px box holding 15px text with 8px
 * of block padding: the height moved and nothing else did. This is the same
 * failure the grid had, in miniature. */
.fx-select-trigger {
    --fx-ctl-h: var(--fx-control-h-lg);
    --fx-ctl-pad-x: var(--fx-control-pad-x-sm);
    --fx-ctl-pad-y: var(--fx-space-2);
    --fx-ctl-radius: var(--fx-radius-md);
    --fx-ctl-font-size: 1em;
    --fx-ctl-leading: var(--fx-leading-snug);
    --fx-ctl-bg: var(--fx-color-field-bg);
    --fx-ctl-fg: var(--fx-color-text);
    /* fx-color-text-placeholder, for the reason section 1 gives at length. */
    --fx-ctl-placeholder: var(--fx-color-text-placeholder);
    --fx-ctl-border: 0;
    --fx-ctl-shadow: var(--fx-shadow-well);

    box-sizing: border-box;
    display: flex;
    align-items: center;
    gap: var(--fx-control-gap-sm);
    inline-size: 100%;
    min-inline-size: 0;
    min-block-size: var(--fx-ctl-h);
    padding-block: var(--fx-ctl-pad-y);
    padding-inline: var(--fx-ctl-pad-x);
    font-family: inherit;
    font-size: var(--fx-ctl-font-size);
    letter-spacing: var(--fx-tracking-ui);
    line-height: var(--fx-ctl-leading);
    /* start, never left: the trigger's label must hug the inline start in both
     * directions, and a <button> defaults to center. */
    text-align: start;
    color: var(--fx-ctl-fg);
    background-color: var(--fx-ctl-bg);
    background-clip: padding-box;
    border: var(--fx-ctl-border);
    border-radius: var(--fx-ctl-radius);
    box-shadow: var(--fx-ctl-shadow);
    cursor: pointer;
    appearance: none;
    transition:
        background-color var(--fx-dur-fast) var(--fx-ease-standard),
        border-color var(--fx-dur-fast) var(--fx-ease-standard),
        box-shadow var(--fx-dur-fast) var(--fx-ease-standard);
}

@media (any-hover: hover) {
    .fx-select-trigger:hover:not(:disabled) {
        --fx-ctl-bg: var(--fx-color-field-bg-hover);
    }
}

.fx-select-trigger:is(:focus, :focus-visible),
.fx-select-trigger[aria-expanded="true"] {
    --fx-ctl-bg: var(--fx-color-field-bg-focus);
}

/* THE CUSTOM SELECT IS A FIELD AND TAKES THE FIELD TREATMENT.
 * It was left on the old detached ring when the glow landed on 2026-08-29,
 * which made the one assembled select on a form look unlike the seven plain
 * inputs beside it — the same inconsistency the input group had. The outline
 * stays declared and transparent so forced-colours can colour it back in. */
.fx-select-trigger:is(:focus, :focus-visible) {
    outline: var(--fx-focus-width) solid transparent;
    outline-offset: var(--fx-focus-offset);
    box-shadow: var(--fx-shadow-field-focus), var(--fx-ctl-shadow);
}

.fx-select-trigger:disabled {
    --fx-ctl-bg: var(--fx-color-disabled-bg);
    --fx-ctl-shadow: none;
    --fx-ctl-fg: var(--fx-color-disabled-fg);
    cursor: not-allowed;
}

/* The selected value. Takes the whole row, truncates with an ellipsis, and never
 * wraps â€” a two line combobox breaks the 40px height the whole form is built on.
 * It reads fx-ctl-fg from the trigger above it, so the disabled state reaches it
 * without a rule of its own. */
.fx-select-trigger > .value,
.fx-select-trigger > .fx-select-value {
    flex: 1;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: start;
    color: var(--fx-ctl-fg);
}

/* An empty combobox reads like an empty text field: TERTIARY, the same tier the
 * placeholder of a form input sits in, so the two are indistinguishable to a
 * user scanning a column of fields. It reads the SAME LOCAL a real placeholder
 * does, so the two cannot drift and a search-styled combobox drops to the
 * quaternary grade by redeclaring one variable. */
.fx-select-trigger > .placeholder,
.fx-select-trigger > .fx-select-placeholder {
    flex: 1;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: start;
    /* The fallback tracks the local's own default, so a trigger outside the
     * locals list still takes the placeholder tier rather than the tier that
     * collapses onto body ink under prefers-contrast. See section 1. */
    color: var(--fx-ctl-placeholder, var(--fx-color-text-placeholder));
}

/* The chevron is QUATERNARY â€” a decorative glyph that carries no information a
 * user has to read, which is exactly what fx-color-text-faint is for. It never
 * shrinks, so a long value truncates instead of squeezing the affordance. */
.fx-select-chevron {
    flex-shrink: 0;
    inline-size: var(--fx-icon-md);
    block-size: var(--fx-icon-md);
    color: var(--fx-color-text-faint);
    background-color: currentColor;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 6 8 10.5 12.5 6l-1.1-1.1L8 8.3 4.6 4.9z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 6 8 10.5 12.5 6l-1.1-1.1L8 8.3 4.6 4.9z'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
    /* fx-dur-quick (120ms) â€” 00-tokens section 7's own reference timing for a
     * chevron rotate, and a real rung on the ladder now, so the literal that
     * used to be written here is gone. The tree disclosure in 06-navigation, the
     * native select's ::picker-icon in 7.0a and this chevron all read the same
     * token, which is the only way three copies of one gesture stay identical.
     * It is nowhere near the banned 200 to 400ms band. */
    transition: transform var(--fx-dur-quick) var(--fx-ease-standard);
}

/* Rotation is symmetric about the block axis, so it needs no RTL mirror. */
.fx-select-trigger[aria-expanded="true"] .fx-select-chevron {
    transform: rotate(180deg);
}


/* 7.2 THE POPUP.
 *
 * THE BACKGROUND ASYMMETRY IS STRUCTURAL, NOT AN INVERSION. In light the popup
 * is LEVEL 3 â€” pure white, above a page and a card that are both tinted. In
 * dark it is LEVEL 2 â€” LIGHTER than the page, because on a near black ground
 * "raised" means "closer to the light". fx-color-surface-raised already encodes
 * exactly that pair (level 3 light, level 2 dark), so the popup reads one token
 * and the asymmetry is maintained in 00-tokens where it belongs.
 *
 * THE GUTTER IS WHAT MAKES A MENU LOOK BUILT. fx-popover-pad is 4px of padding
 * inside the container, around items that carry a 6px radius. Without it the
 * first and last item touch the container edge and the whole panel reads as a
 * list with a border drawn round it rather than as a constructed surface.
 *
 * THE EDGE. A popup is a genuinely floating surface that can land on anything,
 * so its edge comes from the TRANSLUCENT border family (fx-color-border) and not
 * from the opaque divider family. It is allowed to be nearly invisible â€” a
 * container edge identifies nothing, and the SC 1.4.11 obligation in this file
 * is discharged by the trigger's well, not by the panel's outline.
 *
 * WIDTH. At least as wide as the trigger, never narrower than the platform
 * floor. CSS anchor positioning is not shipping everywhere yet, so the anchor
 * width arrives as a custom property that the opening script sets on the popup.
 * That property is fx-anchor-w, the SHARED convention declared in 00-tokens â€”
 * it used to be a local of this component (fx-select-anchor-w) paired with a
 * literal 160px floor, which meant a dropdown, a combobox, a date picker and a
 * command palette would each have invented a property name their own script had
 * to know, and the floor could only be moved by a search across four files. The
 * floor is fx-popover-min-w and the default is 0px WITH ITS UNIT, because max()
 * is type checked and a unitless zero against a px value invalidates the whole
 * declaration. Either way the popup is correct if the property is never set at
 * all, which is its state on first paint and on a page with no script.
 *
 * MOTION. Opacity 0 â†’ 1 plus scale(fx-enter-scale) â†’ 1 over fx-dur-enter (80ms)
 * with fx-ease-standard, leaving over fx-dur-exit (60ms) with fx-ease-in-quad.
 * THE EXIT IS FASTER THAN THE ENTRANCE: a menu that takes as long to leave as it
 * took to arrive feels like it is arguing with the click that dismissed it.
 * The entrance is fx-scale-in, the shared contractual keyframe from 01-base, so
 * a select popup and a popover arrive with the identical curve and distance.
 * transform-origin is anchored to the trigger through fx-select-origin, which
 * the placement script flips to `bottom center` when the popup opens upward. */
.fx-select-popup {
    --fx-select-origin: top center;

    position: absolute;
    inset-inline-start: 0;
    inset-block-start: calc(100% + var(--fx-space-1));
    z-index: var(--fx-z-dropdown);
    display: none;
    box-sizing: border-box;
    min-inline-size: max(var(--fx-anchor-w, 0px), var(--fx-popover-min-w));
    max-inline-size: 100vi;
    max-block-size: min(20rem, 60svh);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--fx-popover-pad);
    color: var(--fx-color-text-muted);
    background-color: var(--fx-color-surface-raised);
    border: var(--fx-border-width) solid var(--fx-color-border);
    border-radius: var(--fx-radius-lg);
    box-shadow: var(--fx-shadow-float-lg);
    transform-origin: var(--fx-select-origin);
}

.fx-select-popup.is-open,
.fx-select-popup[data-fx-open="true"] {
    display: block;
}

/* The container is what the user tabbed to, so the ring stays here â€” see the
 * roving-focus note in section 2.1. */
.fx-select-popup:focus-visible {
    outline: var(--fx-focus-width) solid var(--fx-color-focus-ring);
    outline-offset: calc(var(--fx-focus-offset) * -1);
}

@media (prefers-reduced-motion: no-preference) {
    .fx-select-popup.is-open,
    .fx-select-popup[data-fx-open="true"] {
        animation: fx-scale-in var(--fx-dur-enter) var(--fx-ease-standard);
    }

    /* The script adds .is-closing, waits fx-dur-exit, then removes .is-open. */
    .fx-select-popup.is-closing {
        animation: fx-select-exit var(--fx-dur-exit) var(--fx-ease-in-quad) both;
    }
}

/* Local rather than shared: 01-base has no scale-OUT keyframe, and the exit
 * curve and the exit scale are both properties of this component's dismissal
 * rather than of the shared entrance vocabulary. */
@keyframes fx-select-exit {
    from {
        opacity: 1;
        transform: scale(1);
    }
    to {
        opacity: 0;
        transform: scale(var(--fx-enter-scale));
    }
}


/* 7.3 POPUP ITEMS.
 *
 * THE ICON AND THE LABEL PROMOTE TOGETHER. This is the core Linear signature and
 * the thing most clones miss: at rest an item is a SECONDARY label with a
 * TERTIARY icon; highlighted, it is a PRIMARY label with a PRIMARY icon and a
 * neutral fx-color-active wash behind both. The icon does not stay put while the
 * text brightens â€” the pair moves as one object, which is what makes a keyboard
 * walk down a menu read as a single moving highlight.
 *
 * THE HIGHLIGHT IS GREY, NOT GREEN. A selected or keyboard-highlighted menu item
 * is explicitly named in 00-tokens 3.9 as one of the things people wrongly paint
 * brand. It is fx-color-active, an 8 percent neutral wash.
 *
 * NO RING ON AN ITEM. Roving focus: outline: none plus the wash. See 2.1. */
.fx-select-item {
    display: flex;
    align-items: center;
    gap: var(--fx-control-gap-sm);            /* 8px */
    box-sizing: border-box;
    inline-size: 100%;
    min-block-size: var(--fx-menu-item-h);    /* 32px */
    padding-block: 0;
    padding-inline: var(--fx-control-pad-x-xs);  /* 10px */
    font-size: var(--fx-text-sm);               /* 13px */
    font-weight: var(--fx-weight-regular);
    letter-spacing: var(--fx-tracking-ui);
    line-height: var(--fx-leading-snug);
    text-align: start;
    color: var(--fx-color-text-muted);
    background-color: transparent;
    border: 0;
    border-radius: var(--fx-radius-item);       /* 6px */
    cursor: pointer;
    user-select: none;
    transition:
        color var(--fx-dur-instant) var(--fx-ease-standard),
        background-color var(--fx-dur-instant) var(--fx-ease-standard);
}

.fx-select-item > :is(svg, i, .fx-icon, .fx-select-item-icon) {
    flex-shrink: 0;
    inline-size: var(--fx-icon-md);
    block-size: var(--fx-icon-md);
    color: var(--fx-color-text-subtle);
    transition: color var(--fx-dur-instant) var(--fx-ease-standard);
}

/* The label truncates; nothing else in the row is allowed to. */
.fx-select-item > .fx-select-item-label,
.fx-select-item > .label {
    flex: 1;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (any-hover: hover) {
    .fx-select-item:hover:not([aria-disabled="true"]) {
        color: var(--fx-color-text);
        background-color: var(--fx-color-hover);
    }

    .fx-select-item:hover:not([aria-disabled="true"]) > :is(svg, i, .fx-icon, .fx-select-item-icon) {
        color: var(--fx-color-text);
    }
}

.fx-select-item.is-active,
.fx-select-item[aria-selected="true"],
.fx-select-item:focus,
.fx-select-item:focus-visible {
    outline: none;
    color: var(--fx-color-text);
    background-color: var(--fx-color-active);
}

.fx-select-item.is-active > :is(svg, i, .fx-icon, .fx-select-item-icon),
.fx-select-item[aria-selected="true"] > :is(svg, i, .fx-icon, .fx-select-item-icon),
.fx-select-item:focus > :is(svg, i, .fx-icon, .fx-select-item-icon),
.fx-select-item:focus-visible > :is(svg, i, .fx-icon, .fx-select-item-icon) {
    color: var(--fx-color-text);
}

.fx-select-item[aria-disabled="true"],
.fx-select-item:disabled {
    color: var(--fx-color-disabled-fg);
    background-color: transparent;
    cursor: not-allowed;
}

/* A group heading inside the popup. Tertiary, 11px, and NOT tracked out â€” see
 * the Arabic note in section 6. */
.fx-select-group-label {
    display: block;
    min-block-size: var(--fx-control-h-xs);
    padding-block: var(--fx-space-1);
    padding-inline: var(--fx-control-pad-x-xs);
    font-size: var(--fx-text-2xs);
    font-weight: var(--fx-weight-medium);
    color: var(--fx-color-text-subtle);
}


/* 7.4 THE SEPARATOR â€” it BLEEDS PAST THE GUTTER.
 *
 * The negative inline margin is the detail. Items are inset by fx-popover-pad
 * so their 6px corners float inside the container; a separator that respected
 * the same inset would float too, and a floating 1px line reads as a stray mark
 * rather than as a division. So it is pulled back out by exactly the gutter and
 * touches both interior walls, while the items stay inset. Real Linear tell. */
.fx-select-separator,
.fx-select-popup hr {
    display: block;
    block-size: var(--fx-border-width);
    margin-block: var(--fx-space-1);
    margin-inline: calc(var(--fx-popover-pad) * -1);
    padding: 0;
    background-color: var(--fx-color-divider);
    border: 0;
    opacity: 1;   /* Bootstrap ships hr at .25 */
}


/* â”€â”€ 8) Textarea â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * The fill, the well, the radius, the focus fill and the 12px inline padding all
 * arrive from section 1 â€” a textarea is in that selector list as a bare element,
 * so it is a text control first and a multi line one second. This section only
 * states the three things that are genuinely different about a multi line box:
 * how tall it starts, how it may be resized, and how it grows.
 *
 * HEIGHT. Two control heights, so an empty note field visibly says "more than
 * one line goes here" before anything is typed. Leading is RELAXED rather than
 * snug: the snug 1.35 of section 1 is a control leading meant to sit a single
 * value inside a 40px box, and applying it to a paragraph of Arabic prose is
 * what makes a block of text look cramped. This is the one place in the form
 * layer where prose leading is correct.
 *
 * RESIZE. Block axis only. Horizontal resize would break the grid in section 6
 * and is meaningless for Arabic prose. `vertical` is stated first and `block`
 * second on purpose: they mean the same thing in this platform's writing mode,
 * `block` is the logical spelling this file otherwise uses everywhere, and an
 * engine that does not understand it simply keeps the physical value.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
textarea,
textarea.form-control {
    /* TWO OF THE CONTROL'S OWN HEIGHT, not two of the default step's. Written
     * as `calc(fx-control-h-lg * 2)` this rule pinned every textarea to 80px
     * regardless of the step it was on, so `.form-control-sm` on a textarea
     * moved the padding and the type and left the box the same size as a full
     * one. Reading fx-ctl-h makes the two-row floor a property of the STEP.
     * A self reference is impossible in a custom property, so the multiplier
     * lands on the declaration rather than on the local. */
    min-block-size: calc(var(--fx-ctl-h) * 2);
    padding-block: var(--fx-ctl-pad-y);
    /* Prose leading, set by REDECLARING THE LOCAL rather than by restating
     * line-height: section 1 already paints `line-height: var(fx-ctl-leading)`,
     * and a consumer that redeclares the local on a grid textarea now gets one
     * answer instead of racing this rule. */
    --fx-ctl-leading: var(--fx-leading-relaxed);
    resize: vertical;
    resize: block;
}

/* GROWING WITH THE CONTENT IS NOW THE DEFAULT, NOT AN OPT IN.
 *
 * The client's complaint covered textareas, and this is the substantive part of
 * it. Every multi line field on the platform was a fixed 80px box with its own
 * inner scrollbar: the Cases and Courts dialogs emit `<textarea rows="2">` for
 * the description, the notes and the other-claimants fields, so a lawyer writing
 * three sentences about a case wrote them through a two line window. An opt in
 * class fixed it only for the pages that remembered to ask, and none did.
 *
 * BOUNDED ON BOTH ENDS, which is what makes it safe to turn on everywhere. The
 * floor is the two line minimum above, so an empty field still reads as a
 * textarea rather than collapsing to one line. The ceiling is 22rem, so a
 * pasted contract cannot push the dialog's action buttons off the screen â€” past
 * that the field scrolls, exactly as it does today. The inline axis is not at
 * risk either: section 1a gives every textarea inline-size 100 percent
 * unconditionally, which pins the measure regardless of content.
 *
 * @supports rather than a bare declaration, so the behaviour is announced rather
 * than silently inert: where field-sizing is absent nothing changes at all and
 * the fixed two line box remains. .fx-autosize is kept working for the pages
 * already carrying it, and is now simply redundant. */
@supports (field-sizing: content) {
    textarea,
    textarea.form-control {
        field-sizing: content;
        max-block-size: 22rem;
    }
}

textarea.fx-autosize {
    field-sizing: content;   /* progressive enhancement; ignored where absent */
    max-block-size: 22rem;
}


/* â”€â”€ 9) Native control chrome (dark mode correctness) â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * color-scheme is what makes the platform drawn parts of a control follow the
 * theme: the date picker glyph, the number spinners, the select popup, the
 * search clear button and the inner scrollbar. Without it those stay light on
 * a dark surface and look like a rendering bug.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
:is(.form-control, .form-select, textarea, select, input) {
    color-scheme: light;
}

html[data-bs-theme="dark"] :is(.form-control, .form-select, textarea, select, input) {
    color-scheme: dark;
}


/* â”€â”€ 10) Specialised inputs â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€*/

/* 10.1 Number and any numeric value.
 * Genuine physical direction case, explicitly allowed: a numeric value is read
 * left to right in Arabic too, so the VALUE is forced to ltr while the label,
 * the help text and the surrounding form stay rtl. Tabular figures keep a
 * column of amounts optically aligned.
 *
 * â•â• THE FONT DECLARATION IS GONE, AND ITS ABSENCE IS THE FIX â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * MEASURED IN THE RUNNING APP, case-create dialog, 2026-08-03: the two
 * `input[type=number]` fields (Ø±Ø³ÙˆÙ… ÙØªØ­, Ø§Ù„Ù…Ø¨Ù„Øº Ø§Ù„ÙƒÙ„ÙŠ) computed
 *     font-family: "IBM Plex Sans", "IBM Plex Mono", "Segoe UI", system-uiâ€¦
 * while EVERY sibling field in the same dialog computed
 *     font-family: "IBM Plex Sans Arabic", "IBM Plex Sans", "Noto Kufi Arabic"â€¦
 * Two adjacent fields in one Arabic form were resolving two different font
 * stacks, which is the "from another planet" complaint at the type level rather
 * than the geometry level.
 *
 * THE CAUSE WAS THIS RULE, not the base layer and not the user agent. Section 1
 * already sets `font-family: inherit` on `input[type=number]`, and 01-base's
 * competing `font-family: var(fx-font-numeric)` is the same (0,1,1) specificity
 * in an EARLIER file, so section 1 was already winning. This rule then re-set
 * the Latin stack at (0,1,1) LATER IN THIS FILE and took it straight back.
 * `input[type=tel]` shares 01-base's rule but was never named here, which is
 * why a tel field was correct all along and a number field was not.
 *
 * WHY fx-font-numeric IS THE WRONG TOKEN FOR A FIELD. It is declared Latin
 * first â€” "IBM Plex Sans", then Plex Mono â€” and it exists for numeric COLUMNS
 * and money in table cells, badges and `output`, where nothing Arabic is set
 * beside it. A form field sits inline with Arabic labels and Arabic siblings,
 * so it must resolve the document's own body stack like every other control.
 *
 * AND THE TABULAR FIGURES COST NOTHING TO KEEP. Measured on the running build
 * with both faces force-loaded, at 40px:
 *     "IBM Plex Sans"         0123456789 â†’ 200.00px    1111111111 â†’ 186.64px
 *     "IBM Plex Sans Arabic"  0123456789 â†’ 200.00px    1111111111 â†’ 186.64px
 * IDENTICAL. The two faces are metrically harmonised for Latin digits exactly
 * as 00-tokens claims, so moving a number field off the Latin stack changes no
 * digit advance anywhere â€” the fix is free, not a trade.
 *
 * A KNOWN LIMITATION, RECORDED RATHER THAN HIDDEN: `tabular-nums` is presently
 * INERT on this platform. In the same measurement `1111111111` stayed narrower
 * than `0123456789` in BOTH Plex faces with and without the feature, which means
 * the shipped Plex webfont subsets carry no `tnum` table. The declarations stay
 * because they are correct and cost nothing, and they will start working the day
 * the subset includes the feature. That is a FONT PIPELINE fix, not a form fix â€”
 * see the note at the end of this comment block's section in the handover. */
input[type="number"],
.fx-input-numeric,
.fx-numeric {
    /* STATED, NOT OMITTED. Deleting the line would also work today purely on
     * source order against 01-base, and that is exactly the kind of silent
     * cross-file tie this file refuses to stand on. `inherit` says the intent
     * out loud: a numeric FIELD wears the document's face, like its neighbours. */
    font-family: inherit;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    direction: ltr;
    text-align: start;
}

/* A NUMBER SHOWN IN AN ARABIC PAGE SITS UNDER ITS LABEL, ON THE RIGHT (2026-09-25).
 * The rule above sets `direction: ltr` so the digits keep their order, and `text-align:
 * start` is then resolved against that SAME ltr direction - so every block-level
 * .fx-numeric (an identity number, a phone, a balance in a <dd>) was pushed to the far
 * LEFT, a card's width away from its right-aligned label. Reported on the client file by
 * the owner. `match-parent` was tried first and is not honoured here: measured in Chrome,
 * the computed value stayed `start` and the text stayed left. So the right-to-left case is
 * stated outright. Inputs are excluded: a number FIELD keeps its own alignment, and grid
 * cells carry their own, more specific rule in 09-tabulator. */
html[dir="rtl"] .fx-numeric:not(input) {
    text-align: right;
}

/* Amount style fields read better end aligned inside a two column grid. Same
 * font correction, same reason: it is a field, so it wears the field's face. */
.fx-input-amount {
    font-family: inherit;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    direction: ltr;
    text-align: end;
}

/* â”€â”€ 10.1b) THE TYPED DATE FIELD â€” `.fx-date-input` â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * THIS IS THE REPLACEMENT FOR `input[type=date]`, AND IT IS WHY SECTION 10.2
 * BELOW IS NOW A LEGACY SURFACE RATHER THAN THE PLATFORM'S DATE CONTROL. Read
 * 10.2 first: it records the measurement that forced this, namely that Blink
 * takes the segment order of a native date editor from the BROWSER's UI locale
 * and exposes no author hook of any kind, so eight inputs carrying eight
 * different `lang` values all rendered mm/dd/yyyy on a machine reporting en-US.
 *
 * THE FIELD IS A PLAIN `input[type=text]`, so it is already in section 1's
 * selector list and inherits the whole field system for free: the well, the
 * hover and focus fills, the focus outline, the size steps and the validation
 * border. THIS RULE ADDS NO GEOMETRY AND MUST NEVER ACQUIRE ANY. Height,
 * padding, radius and type size all remain section 1's, reached through the
 * fx-ctl-* locals, exactly as the field contract at the head of this file
 * requires of every consumer.
 *
 * THE FORMAT IS ISO 8601, `yyyy-MM-dd`, and the choice is deliberate against the
 * dd/MM/yyyy that 10.2 originally proposed. Three reasons, in order of weight:
 *
 *   1. IT IS ALREADY WHAT THE GRID PRINTS. The Cases grid's date columns render
 *      the stored value truncated to ten characters, which is ISO. A dialog on
 *      dd/MM/yyyy would have disagreed with the list view of the SAME field, so
 *      the fix would have closed one inconsistency by opening another.
 *   2. DISPLAY FORMAT EQUALS WIRE FORMAT, so the editor performs no conversion
 *      at all and there is no parse step that can regress. On a platform whose
 *      records are legal artefacts that is the property that matters most.
 *   3. A FOUR DIGIT LEADING YEAR CANNOT BE MISREAD. dd/MM/yyyy is unambiguous
 *      only to a reader who already knows the convention, and 03/08/2024 still
 *      reads two ways to a user habituated to the US order, which is the
 *      client's actual complaint. ISO removes the ambiguity structurally.
 *
 * THE VALUE IS `direction: ltr`, for the same reason section 10.1 gives for a
 * number and 10.2 gives for the native editor: a date is read left to right in
 * Arabic. The BOX still sits on the document's axis, so in an RTL form the value
 * is aligned to the field's inline end like every other value on the page.
 *
 * `:dir(rtl)` IS THE CORRECT SELECTOR AND `[dir]` IS NOT, and the physical
 * `right` below is deliberate. Both points are worked through at length in
 * 10.2a: `:dir()` matches HTML directionality and is explicitly NOT affected by
 * the CSS `direction` property, so an input computing `direction: ltr` still
 * matches `:dir(rtl)`; and because the rule is already gated on `:dir(rtl)`,
 * `right` IS the inline end, whereas a logical `end` would resolve against the
 * input's own forced LTR direction and point back at the left. This is the same
 * documented physical exception, applied to the control that replaces it.
 *
 * NOTHING HERE IS A PICKER. The keyboard is the primary input path and the only
 * one required; the format hint travels as a `.fx-help` element wired through
 * `aria-describedby`, which is markup the page owns, not styling this file owes.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.fx-date-input {
    /* Stated rather than omitted, matching `.fx-numeric` immediately above: a
     * date FIELD wears the document's face like its neighbours, and saying so
     * out loud is what stops a later pass reaching for the Latin first numeric
     * stack because the content happens to be digits. */
    font-family: inherit;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    direction: ltr;
    text-align: start;
}

:dir(rtl) .fx-date-input {
    text-align: right;
}

/* ── 10.1b-ii) THE TYPED TIME FIELD — `.fx-time-input` ───────────────────────
 *
 * THE HOUR'S HALF OF 10.1b, AND EVERY WORD ABOVE APPLIES UNCHANGED. It is a
 * plain `input[type=text]`, so it is already in section 1's selector list and
 * inherits the whole field system — well, hover and focus fills, focus outline,
 * size steps, validation border — for free. THIS RULE ADDS NO GEOMETRY AND MUST
 * NEVER ACQUIRE ANY.
 *
 * THE FORMAT IS 24-HOUR `HH:mm`, chosen on the same first ground 10.1b gives for
 * ISO: IT IS ALREADY WHAT THE GRID PRINTS. The appointments column, the visit
 * bookings column, the appointment-schedule report and the delete confirmation
 * all render 24-hour, so an editor on a 12-hour clock disagreed with the list
 * view of the SAME field. Here display format also EQUALS wire format — the
 * payload carries `HH:mm` — so the editor converts nothing at all.
 *
 * Why not `type=time`: section 10.2's measurement covers it. Blink takes the
 * 12/24-hour presentation and the AM/PM segment from the BROWSER's UI locale
 * and exposes no author hook, so on the office's en-US workstations the control
 * painted `--:-- --`. That is the same defect the native date editor had, on the
 * field directly beneath it.
 *
 * `direction: ltr` for the same reason a date and a number take it — an hour is
 * read left to right in Arabic — while the BOX stays on the document's axis, so
 * `:dir(rtl)` puts the value at the field's inline end like every other value.
 * See 10.2a for why `:dir()` is correct where `[dir]` is not, and why the
 * physical `right` below is the deliberate exception rather than a logical `end`.
 *
 * NOTHING HERE IS A PICKER, and unlike the date field there is not even a
 * library one to reach for: bootstrap-datepicker is date-only and no time widget
 * is vendored. The keyboard is the input path; frihat-time-field.js normalises
 * `9:5` and `0930` to `09:30` on blur and refuses anything it cannot read.
 * ────────────────────────────────────────────────────────────────────────── */
.fx-time-input {
    font-family: inherit;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    direction: ltr;
    text-align: start;
}

:dir(rtl) .fx-time-input {
    text-align: right;
}

/* ── 10.1b-iii) THE TIME PICKER PANEL — `.fx-timepicker` ─────────────────────
 *
 * THE ONE FLOATING SURFACE THIS FILE OWNS, and it is here rather than in
 * 07-surfaces because nothing else consumes it: it is part of the time field,
 * built by frihat-time-field.js, and a reader looking for how an hour is
 * collected should find the control and its panel together.
 *
 * IT EXISTS BECAUSE THERE WAS NOTHING TO ADOPT. bootstrap-datepicker ships its
 * own dropdown CSS and the date field inherits it unchanged; there is no
 * vendored time widget, so this panel is hand built and therefore has to name
 * its own surface, border, radius and shadow. Every value below is a TOKEN —
 * no literal colours, no literal radii — so the theme toggle recolours it with
 * no re-render, which is the same contract 12-charts.css keeps.
 *
 * `--fx-z-popover` (1070) AND NOT `--fx-z-dropdown` (1060). These fields live
 * inside dialogs at `--fx-z-modal` (1050), and a 1060 panel clears that today —
 * but popover is the layer meaning "floats above whatever opened it", and using
 * the layer that describes the intent is what keeps a future modal restack from
 * burying the picker.
 *
 * The panel is positioned by script, in document coordinates, so it is
 * `position: absolute` and NOT `fixed`: fixed would detach it from the page
 * during the scroll repositioning the script does, and would need a second
 * coordinate system for no gain.
 * ────────────────────────────────────────────────────────────────────────── */
.fx-timepicker {
    /* The face's geometry, named once here so the ring maths below and the hand
       length agree by construction rather than by three copies of a number. */
    --fx-face-size: 15rem;
    --fx-tick-size: 2.25rem;
    --fx-ring-outer: 5.9rem;
    --fx-ring-inner: 3.9rem;

    position: absolute;
    z-index: var(--fx-z-popover);
    display: none;
    inline-size: max-content;
    padding: var(--fx-space-3);
    background-color: var(--fx-color-surface-raised);
    border: var(--fx-border-width) solid var(--fx-color-border);
    border-radius: var(--fx-radius-xl);
    box-shadow: var(--fx-shadow-float-lg);
}

.fx-timepicker.is-open {
    display: block;
}

/* ── the readout, which is also the mode switch ───────────────────────────── */

.fx-timepicker-readout {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--fx-space-1);
    /* LTR because a clock time is read left to right in Arabic, exactly as
       10.1b argues for the field itself. */
    direction: ltr;
    margin-block-end: var(--fx-space-3);
}

.fx-timepicker-seg {
    padding: var(--fx-space-1) var(--fx-space-2);
    font-family: inherit;
    font-size: var(--fx-text-2xl);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    line-height: 1;
    color: var(--fx-color-text-muted);
    background-color: transparent;
    border: none;
    border-radius: var(--fx-radius-md);
    cursor: pointer;
}

.fx-timepicker-seg:hover {
    background-color: var(--fx-color-primary-subtle);
}

/* The accent names WHICH UNIT THE FACE IS CURRENTLY EDITING — the one piece of
   state a two-mode dial has to make unmistakable. */
.fx-timepicker-seg.is-active {
    color: var(--fx-color-primary);
    background-color: var(--fx-color-primary-subtle);
}

.fx-timepicker-sep {
    font-size: var(--fx-text-2xl);
    font-weight: 600;
    line-height: 1;
    color: var(--fx-color-text-muted);
}

/* ── the face ─────────────────────────────────────────────────────────────── */

.fx-timepicker-face {
    position: relative;
    inline-size: var(--fx-face-size);
    block-size: var(--fx-face-size);
    background-color: var(--fx-color-surface-sunken);
    border-radius: var(--fx-radius-circle);
    /* THE WHOLE FACE IS DRAGGABLE, so the two things a drag would otherwise do
       are turned off: `touch-action` stops a finger scrolling the dialog while
       it is setting the hour, and `user-select` stops a mouse drag painting the
       numerals as selected text. The cursor says the surface is live — the
       numbers are not the only target. */
    touch-action: none;
    user-select: none;
    cursor: pointer;
}

/* ONE RING IS SHOWN AT A TIME and the other is not merely hidden but taken out
   of the hit testing, or the minute ticks would keep catching clicks aimed at
   the hours sitting underneath them. */
.fx-timepicker-ring {
    position: absolute;
    inset: 0;
}

.fx-timepicker[data-mode="hour"] .fx-timepicker-ring[data-ring="minute"],
.fx-timepicker[data-mode="minute"] .fx-timepicker-ring[data-ring="hour"] {
    display: none;
}

/* THE POLAR PLACEMENT, AND THE SECOND ROTATION IS THE POINT. The tick is moved
   to the centre, rotated to its angle, pushed out along the radius, and then
   rotated BACK by the same angle — so it sits on the circle while its digits
   stay upright. Without the counter-rotation every number below the middle of
   the face would be upside down. */
.fx-timepicker-tick {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    inline-size: var(--fx-tick-size);
    block-size: var(--fx-tick-size);
    margin-block-start: calc(var(--fx-tick-size) / -2);
    margin-inline-start: calc(var(--fx-tick-size) / -2);
    font-family: inherit;
    font-size: var(--fx-text-sm);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    color: var(--fx-color-text);
    background-color: transparent;
    border: none;
    border-radius: var(--fx-radius-circle);
    cursor: pointer;
    transform:
        rotate(var(--fx-tick-angle))
        translateY(calc(-1 * var(--fx-ring)))
        rotate(calc(-1 * var(--fx-tick-angle)));
}

.fx-timepicker-tick--outer { --fx-ring: var(--fx-ring-outer); }

/* The inner ring carries 12-23 and is set one grade quieter, so the two halves
   of the day are told apart before a single number is read. */
.fx-timepicker-tick--inner {
    --fx-ring: var(--fx-ring-inner);
    font-size: var(--fx-text-xs);
    color: var(--fx-color-text-muted);
}

.fx-timepicker-tick:hover {
    background-color: var(--fx-color-primary-subtle);
}

.fx-timepicker-tick.is-selected {
    color: var(--fx-color-text-on-primary);
    background-color: var(--fx-color-primary);
}

.fx-timepicker-tick:focus-visible {
    outline: none;
    box-shadow: var(--fx-shadow-focus);
}

/* ── the hand ─────────────────────────────────────────────────────────────── */

/* Anchored at the centre and rotated about its own base, so only the angle has
   to be animated. `pointer-events: none` because it lies across the ticks and
   would otherwise swallow the click it is pointing at. */
.fx-timepicker-hand {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    inline-size: 2px;
    block-size: var(--fx-ring-outer);
    margin-inline-start: -1px;
    background-color: var(--fx-color-primary);
    transform-origin: 50% 0;
    transform: rotate(calc(var(--fx-hand-angle) + 180deg));
    pointer-events: none;
    transition: transform 160ms ease, block-size 160ms ease;
}

/* Shortened onto the inner ring for an afternoon hour, so it points AT the
   number rather than straight through it to the outer one. */
.fx-timepicker-hand.is-inner {
    block-size: var(--fx-ring-inner);
}

.fx-timepicker-hub {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    inline-size: 0.5rem;
    block-size: 0.5rem;
    margin-block-start: -0.25rem;
    margin-inline-start: -0.25rem;
    background-color: var(--fx-color-primary);
    border-radius: var(--fx-radius-circle);
    pointer-events: none;
}

/* Motion is a courtesy, never a requirement. */
@media (prefers-reduced-motion: reduce) {
    .fx-timepicker-hand {
        transition: none;
    }
}

/* ── the footer ───────────────────────────────────────────────────────────── */

.fx-timepicker-foot {
    display: flex;
    justify-content: flex-end;
    gap: var(--fx-space-2);
    margin-block-start: var(--fx-space-3);
}

.fx-timepicker-action {
    padding: var(--fx-space-1) var(--fx-space-3);
    font-family: inherit;
    font-size: var(--fx-text-sm);
    color: var(--fx-color-text);
    background-color: transparent;
    border: var(--fx-border-width) solid var(--fx-color-border);
    border-radius: var(--fx-radius-md);
    cursor: pointer;
}

.fx-timepicker-action:hover {
    background-color: var(--fx-color-primary-subtle);
}

.fx-timepicker-action--primary {
    color: var(--fx-color-text-on-primary);
    background-color: var(--fx-color-primary);
    border-color: var(--fx-color-primary);
}

.fx-timepicker-action--primary:hover {
    background-color: var(--fx-color-primary-hover);
}

.fx-timepicker-action:focus-visible {
    outline: none;
    box-shadow: var(--fx-shadow-focus);
}

/* ── 10.1c) THE SEARCHABLE SELECT — `.fx-select2` ────────────────────────────
 *
 * EVERY DROPDOWN ON THIS PLATFORM IS SEARCHABLE, by the owner's ruling of
 * 2026-08-19, and the reason is the data: the appointment dialog offers 502
 * cases and 501 موكلين. The upgrade is done by frihat-select.js over select2,
 * which ABP's theme-shared bundle already puts on every page — measured in the
 * running build, not assumed.
 *
 * THIS BLOCK EXISTS BECAUSE select2 LOOKS LIKE NOTHING ELSE ON THE PLATFORM.
 * The library draws its own box, caret, dropdown and search field, none of
 * which inherit section 1's field system — so without this the searchable
 * selects would be the one control on the form facing another way, which is
 * precisely the complaint section 10.2 records about the native date editor.
 *
 * EVERY VALUE HERE IS A TOKEN. No literal colours, no literal radii, so the
 * theme toggle recolours the control with no re-render and the contrast
 * decisions stay in 00-tokens where they can be audited.
 *
 * THE HEIGHT IS THE md STEP, matching what the toolbar and the dialogs give a
 * native select, so a searchable select and a plain one sitting side by side in
 * one form are the same size. Nothing here sets a font stack: the control wears
 * the document's face like every other field.
 * ────────────────────────────────────────────────────────────────────────── */

/* FOUR CLASSES, AND EVERY ONE OF THEM IS EARNING ITS KEEP — THIS RULE WAS
 * SILENTLY LOSING IN DARK THEME UNTIL 2026-08-29.
 *
 * LeptonX ships `.lpx-theme-dark .select2-container--default
 * .select2-selection--single { background: #F5F5F7 }` — a NEAR-WHITE fill on a
 * control in a DARK theme, which is a defect in the theme rather than a choice.
 * That selector is three classes; this rule was two, so it lost on specificity,
 * not on source order, and no amount of reordering the bundle would have fixed
 * it. The closed select then painted #F5F5F7 while `.select2-selection__rendered`
 * below correctly took `--fx-color-text` — white text on a white box, measured on
 * the running build at rgb(245,245,247) behind rgb(255,255,255).
 *
 * IT WENT UNSEEN BECAUSE THE ONE PAGE WITH SEARCHABLE SELECTS RE-SKINS THEM
 * ITSELF. Cases/Index.css is page-linked, loads after the bundle AND targets
 * `.select2-container.frihat-select2 …`, so it was covering the gap for the only
 * screen anybody was looking at. The Clients intake dialog was the first select
 * elsewhere, and it exposed the platform-wide fault immediately.
 *
 * `.select2-container.select2-container--default` IS TWO CLASSES ON ONE ELEMENT,
 * DELIBERATELY, and both are always present — measured, not assumed. It buys the
 * fourth point of specificity WITHOUT naming a theme: keying this on
 * `.lpx-theme-dark` would fix the dark case and leave the light one still
 * inheriting a vendor fill, and would put a theme name in a file whose whole
 * contract is that every value is a token and the toggle recolours it.
 *
 * `!important` WAS THE OTHER WAY AND IS NOT USED. It would win everywhere
 * including over the page-level skins that legitimately override this control,
 * and 03-leptonx exists precisely so LeptonX is out-specified rather than
 * shouted down. */
/* ══ WIDENED TO THE LIBRARY'S OWN CLASS, 2026-09-04. THE `fx-` GATE WAS THE
 *    DEFECT, NOT THE CURE. ═══════════════════════════════════════════════════
 *
 * THE OWNER'S REPORT: «أغلب الـdrop down في أغلب الشاشات خلفية بيضا وخط فاتح في
 * وضعية الدارك مود» — most dropdowns on most screens are a white panel carrying
 * light text in dark mode.
 *
 * THE CAUSE, AND IT IS ARCHITECTURAL RATHER THAN A MISSING RULE. Every select2
 * rule in this section used to be keyed on `fx-select2` or `fx-select2-dropdown`
 * — classes THIS PLATFORM ATTACHES, handed to the library by frihat-select.js as
 * `selectionCssClass` and `dropdownCssClass`. A wrapper class only exists where
 * our own script ran. It is absent from every select2 instance ABP, LeptonX or
 * any Volo package creates for itself, and those instances therefore fell all
 * the way through to the library's own stylesheet:
 *
 *     .select2-dropdown { background-color: #fff; border: 1px solid #aaa }
 *
 * A white panel, under a dark theme whose ink is near white. That is the report,
 * exactly. A design system that themes a class it adds itself has made every
 * future usage of the widget a latent bug, so the fix is to key the BASE look on
 * the library's classes and let the wrapper carry only genuine differences.
 * Widening the JavaScript sweep instead would be chasing instances forever.
 *
 * WHERE THE WEIGHT COMES FROM. The vendor, LeptonX and this file all name the
 * same elements, so each rule below states its arithmetic. A repeated class on
 * one element is this file's existing idiom for buying a point of specificity
 * without a flag and without naming a theme — see the note above the selection
 * box and the one above the caret glyph. */

/* NOW (0,4,0) WITHOUT `fx-select2`: three container classes plus `--single`.
 * The class that was dropped was carrying no weight the doubled container does
 * not carry, and it was the only reason an ABP-created select kept LeptonX's
 * near-white fill in dark. */
/* THE SAME FIELD AS THE TEXT BOX BESIDE IT (2026-09-26). This box used to be a
 * surface-coloured card with a 1px stroke while every text, date and search
 * field is the field fill in a soft well with no resting stroke (section 1:
 * --fx-ctl-bg, --fx-ctl-border: 0, --fx-ctl-shadow). Side by side in a filter
 * bar or a dialog grid the two read as different kinds of control. It now
 * paints from the same tokens. The border stays 1px TRANSPARENT rather than 0 so
 * the box keeps its measured size and the hover and focus rules below still
 * have an edge to colour. */
.select2-container.select2-container.select2-container--default .select2-selection--single {
    block-size: var(--fx-control-h-md);
    padding-inline: var(--fx-control-pad-x-sm);
    background-color: var(--fx-color-field-bg);
    border: var(--fx-border-width) solid transparent;
    box-shadow: var(--fx-shadow-well);
    border-radius: var(--fx-radius-md);
    display: flex;
    align-items: center;
}

/* THE INK ON THIS ONE IS NOT OURS, AND AN ATTEMPT TO TAKE IT BACK WAS REVERTED
 * ON 2026-08-29 RATHER THAN SHIPPED. Recorded so nobody spends the hour again.
 *
 * Three rules set this colour, enumerated on the running page:
 *   vendor   (0,3,0) normal      → #444
 *   LeptonX  (0,4,0) !important  → #FFF, dark theme only
 *   this     (0,2,0) normal      → var(--fx-color-text)
 *
 * So `--fx-color-text` never applies. Raising this to (0,5,0) with a doubled
 * class — the idiom Cases/Index.css uses on this very control — wins in LIGHT
 * and CANNOT win in dark, because `!important` is not a specificity contest.
 * That rule was written, measured, and taken out again: a rule that recolours
 * one theme and silently does nothing in the other is the failure that looks
 * like success, and it would have left the platform claiming a token it was not
 * using.
 *
 * IT IS LEFT ALONE BECAUSE THE COST IS COSMETIC AND THE FIX IS NOT. Measured
 * after the background above was corrected: 15.95:1 in dark and 8.91:1 in light,
 * so both clear SC 1.4.3 comfortably. What is wrong is only that the select's
 * writing is #444 where the text input beside it is the token — a different ink,
 * not an unreadable one. Matching it needs an `!important` of our own, which
 * would also beat the page-level skins that legitimately override this control,
 * and that trade is not worth a shade of grey. Revisit if LeptonX ever drops the
 * `!important`, or when the theme bridge in 03-leptonx is next opened.
 *
 * ⚠ AND THIS IS THE ONE RULE IN THE SECTION THAT KEPT ITS `fx-` GATE WHEN
 * EVERYTHING AROUND IT WAS WIDENED ON 2026-09-04. That is deliberate and it is
 * not an oversight to tidy up. Widening it would move it from (0,2,0) to (0,3,0),
 * which is a TIE with the vendor pair above, so it would begin winning `color`,
 * `padding` and `line-height` in LIGHT and would still lose `color` in dark to
 * the flag. That is precisely the outcome the note above records as having been
 * written, measured and then taken out: a rule that recolours one theme and
 * silently does nothing in the other. It would also strip the vendor's caret
 * gutter, which is the only thing keeping the rendered text out from under the
 * arrow. Left as it is, the rule is inert except for `font-size`, and inert is
 * honest here. */
.fx-select2 .select2-selection__rendered {
    padding: 0;
    font-size: var(--fx-text-sm);
    line-height: normal;
    color: var(--fx-color-text);
}

/* The placeholder is a hint and takes the placeholder tier, never body ink —
 * the same split section 16.3 makes for a native control.
 *
 * THIS RULE WAS INERT AT `.fx-select2 …` (0,2,0) EVEN ON OUR OWN INSTANCES. The
 * vendor states the same property at `.select2-container--default
 * .select2-selection--single .select2-selection__placeholder` — (0,3,0) — so the
 * platform placeholder tier never applied anywhere and every searchable select
 * on the product wore the library's #999. Measured against the light panel that
 * is 2.85:1, which fails SC 1.4.3 outright; the token is 4.5:1 or better in all
 * eight themes by construction. Now (0,4,0). */
.select2-container.select2-container.select2-container--default .select2-selection__placeholder {
    color: var(--fx-color-text-placeholder);
}

/* (0,4,0). The vendor has no hover rule for a single selection, so (0,3,0) would
 * have done; the extra point keeps this level with the resting box above, which
 * is the rule it has to be able to modify. */
.select2-container.select2-container--default .select2-selection--single:hover {
    background-color: var(--fx-color-field-bg-hover);
}

/* THE FOCUS RING IS THE PLATFORM'S, not the library's outline. select2 marks
 * focus on the CONTAINER rather than on the rendered box, so the selector has
 * to reach in from there. */
/* KEYED ON select2's OWN CLASSES, NOT ON OUR SKIN CLASS — and that correction
 * is the point of this block.
 *
 * The rule here used to be `.select2-container--focus .fx-select2.select2-
 * selection--single`, and it never matched a single control in the running
 * product. `fx-select2` is handed to select2 as `selectionCssClass` by
 * frihat-select.js, but the containers actually rendered on a grid page carry
 * `frihat-select2` and their selection span carries only the library's own
 * `select2-selection select2-selection--single`. So the platform's searchable
 * dropdown — one of the most-used field shapes in the product, on every grid
 * filter — fell through to 01-base's universal outline and kept the dark green
 * 2px ring after every other field had stopped drawing one. Measured in the
 * browser on /Cases, 2026-08-29.
 *
 * Matching the LIBRARY's classes covers every skin we have and any future one,
 * which is what a vendored widget's integration should have keyed on from the
 * start. `--single` is dropped too so a multi-select behaves the same.
 *
 * THE OUTLINE IS TRANSPARENT, NOT `none` (it was `none` before): that mode
 * drops the box-shadow this rule now relies on, and `none` would leave a
 * forced-colours user with no indicator at all. */
/* THE SELECTION'S OWN :focus IS LISTED FIRST, AND IT IS THE ONE THAT FIRES.
 * `select2-container--focus` is NOT applied on plain keyboard focus — select2
 * adds it on its own focus handling, and tabbing to the control leaves it off,
 * which is why a container-keyed rule tested green in the console (after the
 * class was added by hand) and still painted the dark ring in the running page.
 * The selection span carries `tabindex="0"`, so `:focus` on the span is the
 * honest hook; the two container states stay for the opened and script-focused
 * cases. Verified by tabbing on /Cases, 2026-08-29. */
/* ══ AND THE CONTAINER CLASS IS DOUBLED, BECAUSE A MODULE PAGE RE-SKINS THIS ══
 *
 * `modules/FLP.CaseManagement/.../Pages/Cases/Index.css` paints the select2
 * control itself at `.select2-container.frihat-select2 .select2-selection--single`
 * — (0,3,0) — and a page stylesheet loads AFTER this bundle. So the platform's
 * focus rule at (0,2,0) lost the BOX-SHADOW to that page's resting well while
 * still winning the OUTLINE, which is the confusing half-applied state this was
 * measured in on /Cases: the dark ring correctly gone, the mint glow absent.
 *
 * Doubling the container class takes each arm to (0,4,0), which clears the page
 * skin without a flag. The technique is this file's own — see "THE CLASS IS
 * DOUBLED" in section 2 — and the alternative was worse: chasing the rule into
 * a module stylesheet would put a platform-wide focus decision in one feature's
 * page CSS, where the next module to re-skin select2 would not know to copy it.
 *
 * THE WELL IS COMPOSED BACK IN. This rule replaces box-shadow outright, so
 * naming only the glow would drop the resting depth that identifies the control
 * under SC 1.4.11 at the exact moment it is focused. */
.select2-container.select2-container .select2-selection:is(:focus, :focus-visible),
.select2-container--focus.select2-container--focus.select2-container--focus .select2-selection,
.select2-container--open.select2-container--open.select2-container--open .select2-selection {
    box-shadow: var(--fx-shadow-field-focus), var(--fx-shadow-well);
    outline: var(--fx-focus-width) solid transparent;
    outline-offset: var(--fx-focus-offset);
}

@media (forced-colors: active) {
    .select2-container.select2-container .select2-selection:is(:focus, :focus-visible),
    .select2-container--focus.select2-container--focus.select2-container--focus .select2-selection,
    .select2-container--open.select2-container--open.select2-container--open .select2-selection {
        outline: var(--fx-focus-width) solid Highlight;
        outline-offset: var(--fx-focus-offset);
    }
}

/* THE CARET SITS AT THE INLINE END, which in an RTL form is the LEFT — the same
 * side every other select's chevron sits on, and the thing section 10.2 says
 * the native date editor got wrong. select2 positions its arrow with physical
 * `right`, so the RTL case has to be restated rather than inherited. */
/* NOW (0,5,0), AND THE EXTRA POINTS ARE SPENT ON THE RTL CASE SPECIFICALLY.
 * The vendor positions this arrow twice: `.select2-container--default
 * .select2-selection--single .select2-selection__arrow { right: 1px }` at
 * (0,3,0), and an RTL twin `.select2-container--default[dir=rtl] …` at (0,4,0)
 * that swaps to `left: 1px`. An attribute selector carries class weight, and the
 * document is `dir="rtl"`, so on this platform the (0,4,0) arm is the live one —
 * which the old `.fx-select2 …` rule at (0,2,0) could not touch. The logical
 * properties below therefore did nothing in the language the product is written
 * in. */
.select2-container.select2-container.select2-container--default .select2-selection--single .select2-selection__arrow {
    block-size: 100%;
    inset-inline-end: var(--fx-space-2);
    inset-inline-start: auto;
    inset-block-start: 0;
}

/* THE GLYPH, WHICH THIS FILE POSITIONED BUT NEVER DREW — FOUND 2026-08-29.
 * The rule above places the arrow and stops there, so on every page except one
 * the caret box was 20x26 pixels of nothing: measured on the running build, the
 * vendor's `b` had `border-top: 0px rgba(0,0,0,0)`, no background image and no
 * pseudo-element content. A searchable select that shows no caret reads as a
 * read-only box, so nobody clicks it.
 *
 * IT LOOKED FINE BECAUSE CASES/INDEX.CSS DRAWS ITS OWN. That page skins select2
 * end to end — it also takes the arrow out of absolute positioning — and it was
 * the only screen with searchable selects, so the gap in the shared layer stayed
 * invisible until the Clients intake dialog put one somewhere else.
 *
 * ONLY THE GLYPH MOVES HERE, NOT THE LAYOUT. The Cases page's static/flex
 * treatment of the arrow is a page-level choice about its own field, and lifting
 * that into the bundle would silently relayout a screen nobody asked me to
 * touch. This draws the triangle and leaves the positioning exactly as it was;
 * the page's own rules load later and still win for its layout.
 *
 * LOGICAL EDGES, NOT THE FOUR-VALUE SHORTHAND, matching how Cases/Index.css and
 * the spinner in 09-tabulator build the same kind of shape. A caret's axis is
 * vertical so a physical form would not in fact mirror wrongly in RTL — this is
 * one idiom for one job rather than a bug fix.
 *
 * THE CARET IS A TEXT TIER AND NEVER BRAND: 00-tokens puts a generic icon one
 * step below its label, and the accent contract lists a generic glyph among the
 * forbidden brand sites outright. */
/* THE WEIGHT IS MEASURED, NOT ESTIMATED — this rule was written at (0,2,1) first
 * and lost in exactly the same way the background above did. Enumerating every
 * loaded rule matching this selector on the running page found TWO with the
 * identical selector `.select2-container--default .select2-selection--single
 * .select2-selection__arrow b`: the vendor's, which draws the triangle out of
 * border widths, and a second one — the theme's — that resets it to
 * `border-width: medium; border-color: currentcolor` and sets NO `border-style`,
 * so it computes to `none` and the caret disappears. Both are (0,3,1).
 *
 * `.select2-container.select2-container--default` IS AGAIN TWO CLASSES ON ONE
 * ELEMENT, taking this to (0,4,1) so it clears the reset without `!important`
 * and without naming a theme. */
.select2-container.select2-container.select2-container--default .select2-selection--single .select2-selection__arrow b {
    inline-size: 0;
    block-size: 0;
    border-style: solid;
    border-block-width: var(--fx-border-width-strong) 0;
    border-inline-width: var(--fx-space-1);
    border-block-start-color: var(--fx-color-text-subtle);
    border-block-end-color: transparent;
    border-inline-color: transparent;
}

/* Open: the caret turns over, so the control says which way it is going. The
 * open class joins the same element, giving (0,5,1) against the vendor's own
 * open rule at (0,4,1). */
.select2-container.select2-container.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
    border-block-width: 0 var(--fx-border-width-strong);
    border-block-start-color: transparent;
    border-block-end-color: var(--fx-color-text-subtle);
}

/* ── the dropdown, ON THE LIBRARY'S OWN CLASS ───────────────────────────
 *
 * READ THE WIDENING NOTE ABOVE THE SELECTION BOX FIRST; this is the same defect
 * and the same correction, and this half is the one the owner actually saw.
 *
 * MEASURED IN THE RUNNING BUILD, /ExpenseRequests, dark theme, plum palette,
 * 2026-09-04, on an open dropdown that our own script had NOT created:
 *
 *     panel background  rgb(46,34,45)     correct, from the theme
 *     panel border      rgb(218,207,219)  a LIGHT stroke on a dark panel
 *
 * and on the screens where nothing of ours reached the panel at all it stayed
 * the library's own white, which is the white-panel report.
 *
 * WHERE THE DROPDOWN LIVES, BECAUSE IT DECIDES WHAT THE SELECTORS CAN SEE. This
 * is select2 4.1's AttachBody adapter: the panel is moved out to the document
 * body, or to the dialog when frihat-select.js passes one, wrapped in a bare
 * span whose class attribute is COPIED WHOLESALE from the control's own
 * container. So the panel does sit under `.select2-container.select2-container
 * --default.select2-container--open`, which is exactly why several of the
 * vendor's (0,3,0) descendant rules below reach it and why the old (0,2,0) rules
 * here did not beat them.
 *
 * TWO OF THOSE LOSSES WERE LIVE ON OUR OWN INSTANCES AND ARE FIXED HERE:
 *   · the option highlight, against `.select2-container--default
 *     .select2-results__option--highlighted.select2-results__option--selectable`
 *     at (0,3,0), so every searchable select on the platform highlighted in the
 *     library's own blue except on /Cases, whose page stylesheet happens to
 *     restate it at (0,3,0) and loads later
 *   · the search field's border, against `.select2-container--default
 *     .select2-search--dropdown .select2-search__field` at (0,3,0), the vendor's
 *     grey hairline
 *
 * `.select2-dropdown` IS REPEATED THREE TIMES, WHICH IS ONE MORE THAN THIS FILE
 * USUALLY SPENDS. Two would give (0,2,0) and would only tie whatever painted
 * that light border, leaving source order to decide it; three settles it. The
 * measured border proves something at (0,2,0) or above is in play and it is not
 * in this repository, so a tie is not a risk worth taking for one character.
 *
 * WHAT IS LEFT ON `fx-select2-dropdown`: NOTHING, AND THAT IS THE POINT. The
 * class is still handed to select2 by frihat-select.js and is still the hook for
 * anything genuinely specific to our own initialiser, but nothing in the base
 * look is specific to it. Expressing a rule once, on the library class, is what
 * stops the two copies drifting; a second gated copy would be a second source of
 * truth that nobody would notice going stale.
 * ──────────────────────────────────────────────────────────────────────────── */

/* (0,3,0). `overflow: hidden` is load-bearing rather than tidy: it is what clips
 * the results list, and therefore its scroll rail, inside the panel's own
 * rounded corners. Without it the rail runs past the radius into the square
 * corner of the box, which is half of "the scrollbar is not part of the popup". */
.select2-dropdown.select2-dropdown.select2-dropdown {
    color: var(--fx-color-text);
    background-color: var(--fx-color-surface-raised);
    border: var(--fx-border-width) solid var(--fx-color-border);
    border-radius: var(--fx-radius-md);
    box-shadow: var(--fx-shadow-float-md);
    overflow: hidden;
}

/* THE PANEL JOINS THE CONTROL, AND THAT JOIN HAS TO BE RESTATED HERE NOW.
 * The vendor draws it at `.select2-container--open .select2-dropdown--below`,
 * which is (0,2,0) and so out-specified the old (0,1,0) rule above; the join
 * survived by accident. The rule above is now (0,3,0) and would flatten it, so
 * the join is declared deliberately at (0,4,0) instead of inherited from a
 * library accident. LOGICAL RADIUS CORNERS: the join is on the BLOCK axis, so it
 * does not mirror in RTL, but naming the corners logically keeps one idiom in a
 * file that has no physical edges left anywhere else. */
.select2-dropdown.select2-dropdown.select2-dropdown.select2-dropdown--below {
    border-start-start-radius: 0;
    border-start-end-radius: 0;
    border-block-start-width: 0;
}

.select2-dropdown.select2-dropdown.select2-dropdown.select2-dropdown--above {
    border-end-start-radius: 0;
    border-end-end-radius: 0;
    border-block-end-width: 0;
}

/* THE SCROLLER — THE FIRST HALF OF THE OWNER'S REPORT, AND THE PART THIS FILE
 * DELIBERATELY DOES NOT STYLE.
 *
 * «في سلايد بار قديم ومش مدموج داخل البوباب» — the rail inside the popup
 * is the raw operating system one and is not integrated the way DevExpress
 * integrates its own.
 *
 * NOT ONE `scrollbar-width`, `scrollbar-color` OR `::-webkit-scrollbar` RULE IS
 * WRITTEN HERE, AND THAT IS THE FIX RATHER THAN AN OMISSION. The cause was never
 * local to this component: LeptonXLite sets a light `scrollbar-color` on the
 * body with no theme condition, the property INHERITS, and since Chrome 121 an
 * inherited non-initial value is enough to make Chrome discard every WebKit
 * pseudo element rule for that element. So the platform's whole tokenised
 * scrollbar skin was switched off document-wide by one vendor line, and this
 * popup was simply where it showed. That is corrected once, for every scroller
 * in the product, in 01-base section 11.2. Restating any of it here would create
 * exactly the second convention 01-base forbids, and on the WRONG side of the
 * Chrome 121 rule: declaring `scrollbar-color` on this element would re-disable
 * the pseudo elements for it on the one engine that still uses them.
 *
 * RTL NEEDS NO RULE EITHER, AND THAT WAS VERIFIED RATHER THAN ASSUMED. The rail
 * side follows the scroll container's `direction`. select2 4.1 renders the panel
 * as a span carrying `select2-dropdown` and immediately calls
 * `setAttribute("dir", options.dir)` on it, and `options.dir` is resolved by the
 * library from the element's own `dir`, else from `closest("[dir]")` — which on
 * this platform is the document element, `dir="rtl"`. So EVERY dropdown carries
 * `dir="rtl"`, including the ones ABP creates without passing the option, the
 * results list inherits that direction, and the browser draws the rail on the
 * left of its own accord. Note for the next reader: there is NO
 * `select2-container--rtl` class in 4.1 to key off. That was a 3.x class; the
 * 4.1 container class is built as `"select2-container--" + theme`, and the
 * library's own RTL rules are attribute selectors such as
 * `.select2-container--default[dir=rtl]`. A rule written against the class would
 * match nothing and would look correct in review.
 *
 * WHAT IS LEFT TO DO LOCALLY IS THE INSET. The rail is clipped by the panel's
 * `overflow: hidden` above; this holds it off the rounded ends so it reads as
 * part of the panel rather than as a bar laid across it. `overscroll-behavior`
 * stops a flick at the end of a five-hundred-row list scrolling the page
 * underneath, which on a dialog is how a popup loses its own position. (0,4,0),
 * over the vendor's `.select2-container--default .select2-results >
 * .select2-results__options` at (0,3,0). */
.select2-dropdown.select2-dropdown.select2-dropdown .select2-results > .select2-results__options {
    /* THE LIST PAINTS ITSELF, AND ASSUMING OTHERWISE IS WHAT SHIPPED THE BUG.
     * Styling the PANEL dark was not enough: LeptonXLite paints this inner
     * `ul` too, so the panel's fill never showed through and the list stayed a
     * near-white slab with the theme's light ink on it — the exact "white
     * background, light text" the owner reported three times. Transparent is
     * the right value rather than a repeat of the panel colour: one surface,
     * declared once, on the element that owns it.
     *
     * IT TOOK THREE ROUNDS TO FIND BECAUSE THE VENDOR RULE IS DUPLICATED. The
     * theme ships it in BOTH js-bundle.rtl.css (#f5f5f7) and
     * layout-bundle.rtl.css (#fff), so disabling either one changed nothing and
     * the element read as though no stylesheet controlled it at all. Only
     * disabling every sheet at once, then re-enabling them one by one, named
     * the two. A search for the painted value in one file will not find a
     * defect of this shape.
     *
     * LeptonX does ship `.lpx-theme-dark ...` variants of these rules; they are
     * not winning here. Rather than depend on why, this sets the value at
     * (0,4,0) over the vendor's (0,3,0) so the outcome does not rest on which
     * of the theme's own two copies loads last. */
    background-color: transparent;
    overscroll-behavior: contain;
    scroll-padding-block: var(--fx-space-1);
}

/* Margin on a scrollbar track is the only way to inset a WebKit rail from the
 * ends of its container, and it is inert on the engines that now draw the
 * standard scrollbar instead — harmless there, correct on the fallback engine.
 * A pseudo element adds an ELEMENT point, not a class one, so this is (0,3,1). */
.select2-dropdown.select2-dropdown.select2-dropdown .select2-results__options::-webkit-scrollbar-track {
    margin-block: var(--fx-space-1);
}

/* The search box is a field, so it is given the field's own well rather than
 * the library's bare input. (0,4,0). */
.select2-dropdown.select2-dropdown.select2-dropdown .select2-search--dropdown {
    padding: var(--fx-space-2);
}

/* (0,5,0), over the vendor's (0,3,0) hairline. The old rule here was (0,2,0) and
 * lost, so every search box on the platform carried a grey vendor border on a
 * themed well — one of the two losses named in the block note above. */
.select2-dropdown.select2-dropdown.select2-dropdown .select2-search--dropdown .select2-search__field {
    padding: var(--fx-space-1) var(--fx-space-2);
    font-family: inherit;
    font-size: var(--fx-text-sm);
    color: var(--fx-color-text);
    background-color: var(--fx-color-surface);
    border: var(--fx-border-width) solid var(--fx-color-border);
    border-radius: var(--fx-radius-sm);
}

.select2-dropdown.select2-dropdown.select2-dropdown .select2-search--dropdown .select2-search__field::placeholder {
    color: var(--fx-color-text-placeholder);
}

/* THE OUTLINE IS TRANSPARENT, NOT `none`, for the reason recorded over the
 * selection focus rule further up: `none` drops the box-shadow this relies on in
 * forced colours and would leave that user with no indicator at all. */
.select2-dropdown.select2-dropdown.select2-dropdown .select2-search--dropdown .select2-search__field:is(:focus, :focus-visible) {
    border-color: var(--fx-color-primary);
    box-shadow: var(--fx-shadow-focus);
    outline: var(--fx-focus-width) solid transparent;
    outline-offset: var(--fx-focus-offset);
}

/* THE SELECTOR IS REPEATED IDENTICALLY, NOT WEAKENED. A media query adds no
 * specificity, so this arm only wins because it is the same weight and comes
 * later. Checked deliberately: this codebase has nine recorded cases of a media
 * tier being silently out-specified by a base rule written earlier. */
@media (forced-colors: active) {
    .select2-dropdown.select2-dropdown.select2-dropdown .select2-search--dropdown .select2-search__field:is(:focus, :focus-visible) {
        outline: var(--fx-focus-width) solid Highlight;
        outline-offset: var(--fx-focus-offset);
    }
}

/* (0,4,0). The vendor's own option padding rule is (0,1,0); the weight here is
 * set by the highlight rule below, which this must sit under rather than over. */
.select2-dropdown.select2-dropdown.select2-dropdown .select2-results__option {
    padding: var(--fx-space-2) var(--fx-space-3);
    font-size: var(--fx-text-sm);
    color: var(--fx-color-text);
    background-color: transparent;
}

/* HOVER AND KEYBOARD SHARE ONE TREATMENT. select2 drives both through
 * `--highlighted`, which is correct: a user drives the pointer or the arrow
 * keys, never both, so one paint is one idea.
 *
 * ══ THE FILL IS A TINT NOW, AND THE OLD ONE BROKE THE ACCENT CONTRACT ══════
 *
 * This rule used to paint `fx-color-primary-subtle`. 00-tokens 3.9 names a
 * MENU-ITEM HIGHLIGHT in its forbidden list and answers it with
 * `fx-color-hover`, and it names the exact mistake by hand: "Painting a row
 * hover in green-800 at ten percent is exactly the themed Bootstrap failure this
 * section exists to prevent, and it is still forbidden — a diluted brand is not
 * a tint." `fx-color-primary-subtle` in the light olive theme IS green-800 at ten
 * percent. It measured 1.173:1 against the panel, which is inside the tint band,
 * so it read acceptably and was wrong for a reason no screenshot would show.
 *
 * `fx-color-hover` measures 1.174:1 light and 1.146:1 dark against the raised
 * surface — the same weight, from the interaction family instead of the brand
 * one. The option text over it is 13.92:1 light and 11.28:1 dark.
 *
 * `.select2-results__option--selectable` is appended to match the vendor's own
 * compound and take (0,5,0) rather than tie its (0,3,0) blue. It is also the
 * right condition on its own terms: select2 never highlights a row that cannot
 * be chosen, which includes the truncation hint frihat-select.js appends to a
 * capped remote list. */
.select2-dropdown.select2-dropdown.select2-dropdown .select2-results__option--highlighted.select2-results__option--selectable {
    color: var(--fx-color-text);
    background-color: var(--fx-color-hover);
}

/* The accent is spent on the option currently HELD by the field — one row —
 * which is the smallest spend that answers "what is set". That is 3.9's carve
 * out rather than a stretch of it: the contract sanctions the CHECKED fill of a
 * control because it "REPORTS A VALUE that will be saved", and a chosen option is
 * the same statement in a different shape. Placed after the highlight rule, and
 * at the SAME (0,5,0) weight, so the current value stays legible under the
 * pointer; the state class is repeated rather than a third container class
 * added, because the weight belongs to the state.
 *
 * MEASURED. Light: the on-primary ink is 7.38:1 on the primary fill, and the
 * fill is 8.27:1 against the panel. Dark: 5.16:1 on the fill, and the fill is
 * 2.94:1 against the panel — a hair under the 3:1 that SC 1.4.11 asks of a
 * boundary carrying state. Recorded rather than patched with a local border,
 * because the row is identified by its INK as much as its fill and a border here
 * would be a second, unmeasured decision on tokens another agent is moving this
 * week. Revisit when the palette work lands. */
.select2-dropdown.select2-dropdown.select2-dropdown .select2-results__option--selected.select2-results__option--selected,
.select2-dropdown.select2-dropdown.select2-dropdown .select2-results__option[aria-selected="true"] {
    color: var(--fx-color-text-on-primary);
    background-color: var(--fx-color-primary);
}

/* Unselectable rows — a disabled option, and the "there are more" hint
 * frihat-select.js pushes onto a capped remote result. A hint that reads as a
 * choice is worse than no hint, so it takes a text tier and no fill. (0,4,0)
 * over the vendor's (0,2,0) grey; measured 5.97:1 light and 5.14:1 dark. */
.select2-dropdown.select2-dropdown.select2-dropdown .select2-results__option--disabled {
    color: var(--fx-color-text-subtle);
    background-color: transparent;
}

/* A group label is a heading, not a row: it takes weight and a tier rather than
 * a fill, which is 3.9's Q3 answer. */
.select2-dropdown.select2-dropdown.select2-dropdown .select2-results__group {
    padding: var(--fx-space-2) var(--fx-space-3);
    font-size: var(--fx-text-xs);
    font-weight: var(--fx-weight-semibold);
    color: var(--fx-color-text-subtle);
}

.select2-dropdown.select2-dropdown.select2-dropdown .select2-results__message {
    padding: var(--fx-space-2) var(--fx-space-3);
    font-size: var(--fx-text-sm);
    color: var(--fx-color-text-muted);
}

/* THE CLOSE MASK IS DELIBERATELY NOT PAINTED, AND THE CHECK IS RECORDED SO THE
 * NEXT SWEEP DOES NOT "FIX" IT. select2 lays `.select2-close-mask` over the
 * document to catch the click that dismisses an open dropdown. The library gives
 * it `opacity: 0` alongside its white fill, so the colour is never rendered and
 * the element is a hit target rather than a surface. Reaching for
 * `fx-color-scrim` here would be a regression, not an improvement: it would dim
 * the entire page behind a dropdown, and 00-tokens records that a scrim is a
 * DIFFERENT COLOUR PER THEME — white in light, black in dark — which is a
 * mistake this system has already made once. A dropdown is not a modal. */

/* ── 10.1c) WHY THERE IS NO CUSTOM DATE CONTROL HERE ─────────────────────────
 *
 * A composite control lived at this point on 2026-08-07 and was removed the same
 * day. It is recorded rather than silently deleted, because the next person to
 * read 10.1b and 10.2 will reach for exactly the same idea.
 *
 * THE PLATFORM ALREADY HAS A PICKER. bootstrap-datepicker is vendored under
 * wwwroot/libs and ABP attaches it to every input[type=date], converting the
 * input to 	ype=text so it can draw its own calendar. Anything built here to
 * replace the native editor does not compete with that; it is overwritten before
 * it renders, because the framework has already rewritten the input.
 *
 * AND THE DEFECT WAS NEVER A CONTROL, IT WAS A FORMAT. That library's Arabic
 * locale declares its pattern as d<RLM>/m<RLM>/yyyy: unpadded day and month, with
 * two U+200F RIGHT TO LEFT MARK characters inside the pattern itself. The marks
 * are invisible in an editor and in a debugger, and they reorder the value, so a
 * date held as 7<RLM>/8<RLM>/2026 paints as 72026/8/ on screen. Measured on this
 * build; the char codes were 55, 8207, 47, 56, 8207, 47, 50, 48, 50, 54. The fix
 * is one pattern, applied in frihat-date-field.js, which now does nothing but
 * configure that picker and translate ISO to and from it.
 *
 * So .fx-date-input in 10.1b remains the only class a date field needs, and the
 * calendar affordance belongs to the library rather than to this file.
 * ────────────────────────────────────────────────────────────────────────── */


/* 10.2 Date and time â€” AND THE HONEST LIMIT OF WHAT CSS CAN DO HERE.
 *
 * â•â• THE DEFECT, AS THE CLIENT SEES IT â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * Three `input[type=date]` in the case-create dialog â€” ØªØ§Ø±ÙŠØ® Ø§Ù„ØªÙˆÙƒÙŠÙ„,
 * ØªØ§Ø±ÙŠØ® Ø§Ù„ÙØµÙ„, ØªØ§Ø±ÙŠØ® Ù…ØªÙˆÙ‚Ø¹ â€” rendered Chrome's own segmented editor pinned to
 * the LEFT of the field with the vendor calendar glyph on the RIGHT, inside a
 * dialog where every label, every placeholder and every select chevron runs
 * right to left. In the same screenshot the select directly beneath a date field
 * carried its chevron on the LEFT. The date control was the only thing on the
 * form facing the other way, which is precisely the "from another planet"
 * reading. That part is FIXED below.
 *
 * â•â• WHAT CSS CANNOT FIX, PROVEN RATHER THAN ASSUMED â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * THE mm/dd/yyyy SEGMENT ORDER IS NOT REACHABLE FROM CSS, AND NOT FROM `lang`
 * EITHER. Tested in the running build, eight `input[type=date]` side by side
 * carrying lang="" (none), ar, ar-PS, en-GB, de, fr, ja and en-US. ALL EIGHT
 * rendered `mm/dd/yyyy`, including `ja`, whose locale order is yyyy/mm/dd, and
 * `de`, whose order is dd.mm.yyyy. The document is already `html lang="ar"
 * dir="rtl"` and it changes nothing either. Blink takes the order from the
 * BROWSER's own UI locale â€” here `navigator.language` is "en-US" â€” and exposes
 * no author hook of any kind. There is no pseudo-element for it, no property,
 * and no attribute.
 *
 * SO THE THREE HONEST OPTIONS ARE:
 *   (a) ACCEPT the browser's order. Free, and correct for a user whose browser
 *       is Arabic or British; wrong for the Frihat office as configured today,
 *       where every workstation reports en-US and a Palestinian lawyer is shown
 *       a US month-first date on a legal record.
 *   (b) SET `lang` ON THE INPUT. DEAD â€” measured above. It does nothing. Do not
 *       spend a task on it, and do not let a code review ask for it again.
 *   (c) STOP USING `type="date"` and render `type="text"`, formatting and
 *       parsing one explicit format.
 *
 * â•â• (c) SHIPPED, 2026-08-03. SEE SECTION 10.1b â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * The three case dialog fields â€” ØªØ§Ø±ÙŠØ® Ø§Ù„ØªÙˆÙƒÙŠÙ„, ØªØ§Ø±ÙŠØ® Ø§Ù„ÙØµÙ„, ØªØ§Ø±ÙŠØ® Ù…ØªÙˆÙ‚Ø¹ â€” are
 * now `input[type=text].fx-date-input` on ISO `yyyy-MM-dd`, parsed and validated
 * by the page. 10.1b carries the component and the reasoning; the short version
 * is that ISO was chosen over the dd/MM/yyyy this note originally proposed
 * because ISO is ALREADY what the grid column prints and what the payload
 * carries, so the editor converts nothing and no parse step can regress.
 *
 * A FOURTH OPTION WAS EVALUATED AND REJECTED ON EVIDENCE: adopting the
 * bootstrap-datepicker that ABP vendors and loads globally. It is genuinely
 * present and genuinely supported â€” there is an `abp.libs.bootstrapDatepicker`
 * wrapper and an Arabic locale file â€” but measured in the running build under
 * culture `ar` its wrapper formats a value through
 * `luxon.DateTime.toLocaleString()`, turning `2024-03-08` into `8â€/3â€/2024`:
 * day first, unpadded, and carrying embedded U+200F RIGHT TO LEFT MARK
 * characters, with the widget's own `format` reading `dâ€/mâ€/yyyy`. That string
 * is what would have reached the wire. It is unparseable at best and a silent
 * day/month transposition at worst, and it is still LOCALE derived, which is the
 * same class of defect as Blink's mm/dd/yyyy merely relocated. Do not revisit.
 *
 * â•â• WHAT THE RULES BELOW ARE STILL FOR â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * They are retained and unchanged. `input[type=date]` is no longer emitted by
 * the case dialog, but the type is still reachable from ABP's own scaffolded
 * pages, from a future module, and from `time`, `datetime-local`, `month` and
 * `week`, none of which section 10.1b replaces. A platform control must not
 * render unstyled the day somebody uses it, so the native surface keeps its
 * skin. What it no longer is, is the way this product asks for a date.
 *
 * â•â• WHAT IS FIXED BELOW â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * The VALUE stays `direction: ltr` â€” a date is read left to right in Arabic for
 * the same reason a number is, and section 10.1 states that case. What changes
 * is the BOX: in an RTL document the segmented editor now sits at the inline
 * END of the field like every other value, and the picker affordance sits at the
 * inline START like every select chevron on the platform.
 *
 * `:dir(rtl)` IS THE CORRECT SELECTOR AND `[dir]` IS NOT. `:dir()` matches the
 * element's HTML directionality, which it inherits from `html dir="rtl"`, and it
 * is explicitly NOT affected by the CSS `direction` property. Verified in the
 * running build: a date input with computed `direction: ltr` still matches
 * `:dir(rtl)`. That is the whole trick â€” it lets the segments keep their LTR
 * reading order while the field is laid out on the document's axis. A `[dir]`
 * attribute selector would match nothing, because no field on this platform
 * carries the attribute; only the root does. */
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"],
input[type="week"] {
    /* THE PICKER AFFORDANCE'S OWN GEOMETRY, held in locals for the same reason
     * every other geometry in this file is: a consumer on a size step retunes
     * the variable, never the rule. A pseudo-element inherits custom properties
     * from its originating element, which is what lets the indicator read these
     * â€” the same mechanism section 10.4 relies on for the file trigger.
     *
     * THE SIZE IS AN SC 2.5.8 FLOOR, NOT A TASTE. Section 10.3 works through
     * this exact calculation for the search cancel button and concludes that the
     * conformant states are a 24px target or NO target, because `appearance:
     * none` plus authored dimensions forfeits the user-agent-control exemption.
     * The cancel button could be hidden because `.fx-input-action` replaces it.
     * THE CALENDAR INDICATOR CANNOT: hiding it removes the only pointer route to
     * the picker, and there is no author-side replacement for a UA popup. So it
     * is floored at fx-control-h-xs â€” 24px fine, 28px coarse â€” the same floor
     * `.fx-input-action` carries. Measured after: a 40px field stays 40px, so
     * the floor costs no height on the default step. */
    --fx-ctl-picker-size: var(--fx-control-h-xs);
    /* The artwork inside that target. fx-icon-md is the platform's default glyph
     * step and the size the select chevron already draws at, so the two
     * affordances on adjacent fields match without anybody measuring. */
    --fx-ctl-picker-glyph: var(--fx-icon-md);
    --fx-ctl-picker-radius: var(--fx-radius-xs);

    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    direction: ltr;
    text-align: start;
}

/* â”€â”€ 10.2a The segmented editor, placed on the form's axis â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * EVERY WEBKIT PSEUDO-ELEMENT BELOW GETS ITS OWN RULE, NEVER A SHARED SELECTOR
 * LIST WITH A STANDARD SELECTOR. A selector list containing a pseudo-element the
 * engine does not know is INVALID IN ITS ENTIRETY, so one `::-webkit-â€¦` smuggled
 * into a grouped rule would delete that rule for every Gecko user. Firefox draws
 * no segmented editor at all, so it correctly drops these and loses nothing.
 * This is the same discipline that keeps section 16's accessibility tiers safe,
 * and it is why the reduced-motion, contrast, forced-colours and print branches
 * further down each carry a SEPARATE webkit rule rather than an extra line in
 * the list beside them.
 *
 * flex: 1 1 auto IS LOAD BEARING. Blink lays the shadow tree out as a flex row
 * of [ datetime-edit ][ picker indicator ]. Without the grow the editor is
 * shrink-to-fit and `text-align` has no free space to move the value into, so
 * the value stays pinned to the start however the rest is written. Measured
 * every branch: `direction: rtl` on the input alone moves NOTHING, on the edit
 * alone moves NOTHING, and `margin-inline-*: auto` on either moves NOTHING â€”
 * the grow plus a physical alignment is the only combination that works. */
:dir(rtl) input[type="date"]::-webkit-datetime-edit {
    flex: 1 1 auto;
    /* PHYSICAL, AND THAT IS DELIBERATE â€” the fourth documented physical
     * exception in this file, joining the switch knob travel, the numeric value
     * direction and the validation summary offset. This rule is already gated on
     * `:dir(rtl)`, so "right" IS the inline end for every element it can reach;
     * `end` would resolve against the editor's own forced-LTR direction and
     * point back at the left, which is the bug being fixed. */
    text-align: right;
}

:dir(rtl) input[type="time"]::-webkit-datetime-edit {
    flex: 1 1 auto;
    text-align: right;
}

:dir(rtl) input[type="datetime-local"]::-webkit-datetime-edit {
    flex: 1 1 auto;
    text-align: right;
}

:dir(rtl) input[type="month"]::-webkit-datetime-edit {
    flex: 1 1 auto;
    text-align: right;
}

:dir(rtl) input[type="week"]::-webkit-datetime-edit {
    flex: 1 1 auto;
    text-align: right;
}

/* THE AFFORDANCE MOVES TO THE INLINE START, VIA `order`, WHICH IS THE ONE
 * MECHANISM THE SHADOW TREE HONOURS. The indicator is the second flex item, and
 * neither `direction` nor an auto margin relocates it â€” tested, both inert.
 * `order: -1` moves it, and it is the only thing that does. The target is the
 * left edge in Arabic because that is where this platform already puts a field's
 * affordance: the `.fx-select-chevron` in section 7.1 and the native select's
 * own icon both sit there, and a date field two rows above a select must not
 * disagree with it. */
:dir(rtl) input[type="date"]::-webkit-calendar-picker-indicator {
    order: -1;
}

:dir(rtl) input[type="time"]::-webkit-calendar-picker-indicator {
    order: -1;
}

:dir(rtl) input[type="datetime-local"]::-webkit-calendar-picker-indicator {
    order: -1;
}

:dir(rtl) input[type="month"]::-webkit-calendar-picker-indicator {
    order: -1;
}

/* WEEK IS IN EVERY ONE OF THESE LISTS, AND IT WAS NOT BEFORE. The rule this
 * replaced styled date, time, datetime-local and month and stopped there, which
 * cost nothing while the glyph was the vendor's in all five cases. It stops
 * being free the moment 10.2b redraws four of them: a `type=week` field would
 * keep Blink's icon, on the wrong edge, beside four fields carrying ours. That
 * is the "half migrated field" section Z names as a worse outcome than losing
 * outright, and it would appear the first time a page uses the type rather than
 * at review. Section 1 already gives week the fx-ctl-* locals, so it belongs in
 * every list in this section. */
:dir(rtl) input[type="week"]::-webkit-calendar-picker-indicator {
    order: -1;
}

/* â”€â”€ 10.2b The affordance is OURS now, not the vendor's â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * A product that draws its own chevron, its own tick, its own eye and its own
 * warning triangle has no business shipping one Blink icon in the middle of a
 * form. The glyph is replaced with a masked calendar in the platform's own
 * drawing, at the platform's own icon step, in a NEUTRAL text tier â€” the same
 * treatment `.fx-select-chevron` gets, for the same reason. NO BRAND: this file
 * spends its two sanctioned accents on the text caret and the checked control,
 * and an affordance glyph is neither.
 *
 * `background-image: none` is what removes the vendor artwork; the mask then
 * paints `background-color` through the glyph shape. `opacity: 1` is required
 * because Blink dims the indicator by default and a masked glyph inherits that
 * dimming as a contrast loss.
 *
 * HIT TESTING SURVIVES ALL OF THIS, VERIFIED RATHER THAN ASSUMED. Every property
 * here is paint or layout; `pointer-events` is never touched and the element is
 * never `display: none`. Measured in the running build by instrumenting the
 * window blur that Chrome fires when the native picker takes focus: clicking the
 * restyled indicator produced the IDENTICAL signature to clicking a pristine
 * unstyled one. The picker still opens. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator,
input[type="week"]::-webkit-calendar-picker-indicator {
    box-sizing: border-box;
    flex: none;
    inline-size: var(--fx-ctl-picker-size);
    block-size: var(--fx-ctl-picker-size);
    /* The floor is on the ELEMENT, not on a wrapper, so a consumer that shrinks
     * the glyph cannot shrink the target underneath it. */
    min-inline-size: var(--fx-ctl-picker-size);
    min-block-size: var(--fx-ctl-picker-size);
    padding: 0;
    margin: 0;
    border-radius: var(--fx-ctl-picker-radius);
    opacity: 1;
    color: var(--fx-color-text-subtle);
    background-color: currentColor;
    background-image: none;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M5.25 1v1.25h5.5V1h1.5v1.25H14A1.25 1.25 0 0 1 15.25 3.5V14A1.25 1.25 0 0 1 14 15.25H2A1.25 1.25 0 0 1 .75 14V3.5A1.25 1.25 0 0 1 2 2.25h1.75V1h1.5zM13.75 6.5H2.25V13.75h11.5V6.5zM4.5 8.25h2v2h-2v-2zm3.5 0h2v2H8v-2z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M5.25 1v1.25h5.5V1h1.5v1.25H14A1.25 1.25 0 0 1 15.25 3.5V14A1.25 1.25 0 0 1 14 15.25H2A1.25 1.25 0 0 1 .75 14V3.5A1.25 1.25 0 0 1 2 2.25h1.75V1h1.5zM13.75 6.5H2.25V13.75h11.5V6.5zM4.5 8.25h2v2h-2v-2zm3.5 0h2v2H8v-2z'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    /* The TARGET is fx-ctl-picker-size and the ARTWORK is fx-ctl-picker-glyph â€”
     * the same "24px box, 16px drawing" split section 12 uses for a checkbox and
     * section 10.3 explains at length. The mask is what keeps them independent. */
    -webkit-mask-size: var(--fx-ctl-picker-glyph) var(--fx-ctl-picker-glyph);
    mask-size: var(--fx-ctl-picker-glyph) var(--fx-ctl-picker-glyph);
    cursor: pointer;
    transition:
        color var(--fx-dur-fast) var(--fx-ease-standard),
        background-color var(--fx-dur-fast) var(--fx-ease-standard);
}

/* Promotes one text tier on hover, exactly like `.fx-input-action`. The fill
 * wash the previous version painted is GONE: `background-color` is the mask's
 * paint source now, so a hover wash there would recolour the GLYPH rather than
 * light a plate behind it. Colour alone is the correct feedback for a masked
 * affordance, and it is the same feedback the chevron gives. */
@media (any-hover: hover) {
    input[type="date"]::-webkit-calendar-picker-indicator:hover {
        color: var(--fx-color-text);
    }

    input[type="time"]::-webkit-calendar-picker-indicator:hover {
        color: var(--fx-color-text);
    }

    input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover {
        color: var(--fx-color-text);
    }

    input[type="month"]::-webkit-calendar-picker-indicator:hover {
        color: var(--fx-color-text);
    }

    input[type="week"]::-webkit-calendar-picker-indicator:hover {
        color: var(--fx-color-text);
    }
}

/* ── 10.2b) THE CALENDAR POPUP — bootstrap-datepicker ─────────────────────
 *
 * ══ THE DEFECT, AS THE OWNER REPORTED IT, 2026-09-04 ═════════════════════
 *
 * «نفس الاشي بحقول التاريخ الكالندر احيانا بكون لايت بالدارك مود» — the same
 * thing on the date fields: the calendar is sometimes light in dark mode.
 *
 * ══ THE WORD "SOMETIMES" IS THE DIAGNOSIS, NOT A HEDGE ══════════════════
 *
 * THIS WIDGET WAS ZERO PERCENT THEMED. Before this section, a search of every
 * stylesheet in `wwwroot/css/frihat` for a selector containing `datepicker`
 * returned NOTHING. The four occurrences of the word in this file were all
 * prose inside comments — including the note above, which says the library is
 * vendored and loaded globally and then never styles it. select2 at least had
 * rules that were reaching the wrong instances; this had none at all.
 *
 * SO THE PANEL WAS HALF CORRECT AND THE CONTENTS WERE NOT, WHICH IS EXACTLY
 * WHAT "SOMETIMES" LOOKS LIKE. The outer element carries Bootstrap's
 * `dropdown-menu` as well as `datepicker`, so wherever the platform's own
 * dropdown surface reaches `.dropdown-menu` the FRAME darkens — but the day
 * cells, the weekday header, the month and year grid, the hover state and the
 * selected day are raw library CSS and never darken at all. The widget therefore
 * reads acceptably on one screen and obviously broken on the next, depending on
 * what else happens to be in the cascade there. THE CELLS ARE THE TARGET; a fix
 * that only darkened the frame would reproduce the same report.
 *
 * WHAT THE LIBRARY ACTUALLY SHIPS, from `bootstrap-datepicker.min.css` v1.10.1:
 *   · four separate `background: #eee` rules — day hover, month hover, the
 *     header arrows and the footer buttons
 *   · a Bootstrap-2 era blue gradient on the SELECTED day, written six times
 *     over for the vendor prefixes of 2012, ending in an IE filter
 *   · a yellow gradient on TODAY, on the same pattern
 *   · grey ink on the leading and trailing days of the adjacent months
 * None of it has a theme condition, because the library predates the idea.
 *
 * ══ WHICH WIDGET IS ON WHICH FIELD — THERE ARE TWO, AND THEY FAIL DIFFERENTLY
 *
 * A date field on this platform is one of two things and the distinction decides
 * where a fix belongs:
 *
 *   1. THE LIBRARY WIDGET. `input.fx-date-input`, or an `input[type=date]` that
 *      ABP's own initialiser swept and flipped to `type=text`. Both end up
 *      attached to bootstrap-datepicker, which draws the calendar below as
 *      ordinary DOM. THIS SECTION IS THAT CASE, and it is the common one: the
 *      typed field itself measured correct in dark on /ExpenseRequests, so what
 *      the owner is seeing is this POPUP rather than the field.
 *   2. THE NATIVE CONTROL. An `input[type=date]` that neither sweep reached —
 *      ABP's initialiser only walks page content and never sees markup a dialog
 *      built, and frihat-date-field.js runs no sweep of its own; a dialog is
 *      enhanced only where its own script calls `enhance`. That calendar is
 *      drawn by the browser and NO author CSS can reach inside it. Its one lever
 *      is `color-scheme`, which section 9 above already declares on every input
 *      in both themes. If a native picker is ever found rendering light in dark
 *      mode, the fix is there and never here.
 *
 * ══ EVERY VALUE IS A SEMANTIC TOKEN, AND THAT IS WHAT MAKES IT EIGHT-THEME ═
 *
 * The platform is four palettes crossed with light and dark. A rule written
 * against `fx-color-*` is correct in all eight for free; a literal or a
 * `fx-p-*` primitive would be right in one and wrong in the other seven. There
 * is not a single colour literal below.
 *
 * ══ THE ACCENT CONTRACT, APPLIED RATHER THAN ASSUMED (00-tokens 3.9) ═════
 *
 * Three states, three different answers, and they are not interchangeable:
 *
 *   · A HOVERED OR KEYBOARD-FOCUSED DAY answers Q2 — the pointer is here — so it
 *     is a TINT: `fx-color-hover`. 3.9 lists a menu-item highlight in its
 *     forbidden column by name, and forbids a diluted brand there explicitly.
 *   · TODAY answers Q1 — where I currently am — but it is not the field's value
 *     and nothing is saved by it, so under Q1a it is a MARK DRAWN ON a plane
 *     that already exists, never a fill: an inset hairline in
 *     `fx-color-indicator` with the numeral in `fx-color-brand-text`. Measured
 *     on the raised surface, the ring is 8.27:1 light and 5.01:1 dark against
 *     the panel, both clear of the 3:1 that SC 1.4.11 asks of a boundary; the
 *     numeral is 8.27:1 light and 9.47:1 dark.
 *   · THE SELECTED DAY is the brand FILL, and it is the only one. It REPORTS A
 *     VALUE THAT WILL BE SAVED, which is the same job 3.9 sanctions for the
 *     checked fill of a checkbox and for the chosen option in a dropdown. One
 *     cell in the panel, bounded, exactly as the select2 block above spends it.
 *
 * ══ RTL ═════════════════════════════════════════════════════════
 *
 * THE LIBRARY FORCES `direction: ltr` ON ITS OWN PANEL and only restores it
 * through a `datepicker-rtl` class that it adds when the ACTIVE LOCALE declares
 * `rtl: true`. The bundled `ar` locale does declare it and frihat-date-field.js
 * also passes `rtl: true`, so the common path is correct — but it is correct by
 * two coincidences, and an instance created by other code under a locale that
 * does not carry the flag would open a right-to-left form with a left-to-right
 * calendar in it. `direction: inherit` below takes the answer from the document
 * instead, which is right in Arabic and right in English without either flag.
 * The month and year cells are taken off `float` for the same reason: a float is
 * a physical instruction that has to be mirrored by hand, and the library
 * mirrors it only inside that same `datepicker-rtl` class.
 * ──────────────────────────────────────────────────────────────────────────── */

/* ══ THE ARITHMETIC, STATED ONCE FOR THE WHOLE SECTION ══════════════════
 *
 * `.datepicker` IS REPEATED THREE TIMES ON EVERY RULE BELOW. That is not a
 * flourish; it is the smallest prefix that clears what the library actually
 * ships. Enumerated from the vendor stylesheet rather than estimated:
 *
 *     .datepicker                                          (0,1,0)
 *     .datepicker td, .datepicker th                        (0,1,1)
 *     .datepicker table tr td.new / .old                    (0,2,3)
 *     .datepicker table tr td.day:hover                     (0,3,3)
 *     .datepicker table tr td.disabled:hover                (0,4,3)
 *     .datepicker table tr td.today.disabled:hover.disabled (0,5,3)  ← the ceiling
 *     .datepicker table tr td span.active.disabled:hover.disabled     (0,5,4)
 *
 * A three-class prefix plus a repeated STATE class reaches (0,6,3) and (0,6,4),
 * which clears the ceiling in both families without a single importance flag.
 * The state class is what gets repeated rather than a fourth `.datepicker`,
 * because the weight belongs to the state: it is what lets `active` and
 * `disabled` be ordered against each other at equal weight by source position,
 * which is the readable way to say "a disabled day is never shown as chosen".
 *
 * WHY NOT `!important`. It would beat the page stylesheets that legitimately
 * re-skin a control on their own screen, and this file's whole posture is that
 * a vendor is out-specified rather than shouted down. ══════════════════ */

/* THE PANEL. (0,3,0) over the library's (0,1,0) and over its `datepicker-rtl`
 * direction override, which is also (0,1,0). */
.datepicker.datepicker.datepicker {
    direction: inherit;
    padding: var(--fx-space-2);
    font-size: var(--fx-text-sm);
    color: var(--fx-color-text);
    background-color: var(--fx-color-surface-raised);
    border: var(--fx-border-width) solid var(--fx-color-border);
    border-radius: var(--fx-radius-md);
    box-shadow: var(--fx-shadow-float-md);
}

/* THE LITTLE POINTER AT THE FIELD. The library draws it as two stacked CSS
 * triangles: an outer one in a grey that stands for the border and an inner one
 * in white that stands for the panel fill. Both were literals, so in dark mode
 * the widget grew a white spike out of a dark panel. (0,4,1) over the vendor's
 * (0,1,1); the orientation twins below are (0,5,1) over its (0,2,1). */
.datepicker.datepicker.datepicker.datepicker-dropdown::before {
    border-block-end-color: var(--fx-color-border);
}

.datepicker.datepicker.datepicker.datepicker-dropdown::after {
    border-block-end-color: var(--fx-color-surface-raised);
}

.datepicker.datepicker.datepicker.datepicker-dropdown.datepicker-orient-top::before {
    border-block-start-color: var(--fx-color-border);
}

.datepicker.datepicker.datepicker.datepicker-dropdown.datepicker-orient-top::after {
    border-block-start-color: var(--fx-color-surface-raised);
}

/* THE HEADER ROW — the month name and the two arrows — and the footer button.
 * They are interactive, so they take the tint and nothing else. (0,5,0) over the
 * vendor's (0,3,0). */
.datepicker.datepicker.datepicker .datepicker-switch,
.datepicker.datepicker.datepicker .prev,
.datepicker.datepicker.datepicker .next,
.datepicker.datepicker.datepicker tfoot tr th {
    font-weight: var(--fx-weight-medium);
    color: var(--fx-color-text);
    background-color: transparent;
    border-radius: var(--fx-radius-item);
    transition: background-color var(--fx-dur-fast) var(--fx-ease-standard);
}

@media (any-hover: hover) {
    .datepicker.datepicker.datepicker .datepicker-switch:hover,
    .datepicker.datepicker.datepicker .prev:hover,
    .datepicker.datepicker.datepicker .next:hover,
    .datepicker.datepicker.datepicker tfoot tr th:hover {
        background-color: var(--fx-color-hover);
    }
}

/* THE WEEKDAY HEADING AND THE WEEK NUMBER. Neither answers Q1 or Q2, so both
 * take a text tier and no colour of their own — 3.9's third answer, which is
 * where most of a product lives. */
.datepicker.datepicker.datepicker thead tr th.dow,
.datepicker.datepicker.datepicker .cw {
    font-size: var(--fx-text-xs);
    font-weight: var(--fx-weight-medium);
    color: var(--fx-color-text-subtle);
}

/* THE DAY CELL AT REST. (0,3,3), which is deliberately BELOW every state rule
 * that follows so a state can modify it. The radius is the platform's list-row
 * radius, so a hovered day is the same shape as a hovered menu row. */
.datepicker.datepicker.datepicker table tr td,
.datepicker.datepicker.datepicker table tr td span {
    color: var(--fx-color-text);
    background-color: transparent;
    border-radius: var(--fx-radius-item);
    transition: background-color var(--fx-dur-fast) var(--fx-ease-standard);
}

/* THE MONTH AND YEAR GRID FLOWS BY DIRECTION, NOT BY A FLOAT. See the RTL note
 * in the section header. (0,4,4) over the vendor's (0,1,4) float and over the
 * `datepicker-rtl` mirror of it, which is also (0,1,4). The width and margin the
 * library sets are untouched, so four still fit on a row. */
.datepicker.datepicker.datepicker.datepicker table tr td span {
    float: none;
    display: inline-block;
    vertical-align: top;
}

/* THE DAYS OF THE ADJACENT MONTHS. Present so the grid is a rectangle, but not
 * this month, so they drop one tier. (0,4,3) over the vendor's (0,2,3); measured
 * 5.97:1 light and 5.14:1 dark on the raised surface, so they stay readable
 * rather than becoming decoration. */
.datepicker.datepicker.datepicker table tr td.old,
.datepicker.datepicker.datepicker table tr td.new,
.datepicker.datepicker.datepicker table tr td span.old,
.datepicker.datepicker.datepicker table tr td span.new {
    color: var(--fx-color-text-subtle);
}

/* HOVER AND KEYBOARD SHARE ONE TREATMENT, exactly as they do in the dropdown
 * above: the library drives both through `focused` and `:hover`, and a user
 * drives the pointer or the arrow keys but never both. THE TINT, NOT THE BRAND
 * — see the accent note in the section header. (0,5,3) and (0,5,4) over the
 * vendor's (0,3,3) and (0,2,4) grey. */
.datepicker.datepicker.datepicker table tr td.day:hover,
.datepicker.datepicker.datepicker table tr td.day.focused,
.datepicker.datepicker.datepicker table tr td span:hover,
.datepicker.datepicker.datepicker table tr td span.focused {
    color: var(--fx-color-text);
    background-color: var(--fx-color-hover);
    cursor: pointer;
}

/* TODAY IS A MARK, NOT A FILL. An inset hairline rather than a background, so it
 * composes with the hover tint instead of fighting it: hovering today shows the
 * tint AND keeps the ring, which is the behaviour a fill could not give without
 * a fourth rule. `box-shadow: inset` rather than `border`, because a border on a
 * table cell shifts the grid by a pixel and the ring must not move the calendar.
 * (0,6,3) and (0,6,4), over the vendor's (0,5,3) and (0,5,4) yellow gradient. */
.datepicker.datepicker.datepicker table tr td.today.today.today,
.datepicker.datepicker.datepicker table tr td span.today.today.today {
    color: var(--fx-color-brand-text);
    background-color: transparent;
    /* BACKGROUND-COLOR DOES NOT CANCEL A BACKGROUND-IMAGE, AND THAT OMISSION
     * SHIPPED. The library paints today with
     * `linear-gradient(#fdd49a, #fdf59a)` — an amber that belongs to no theme
     * here — and a gradient is drawn ON TOP of the colour beneath it. Setting
     * the colour to transparent therefore changed nothing a user could see: on
     * a plum dark panel the cell stayed bright amber with a pink numeral on it,
     * measured in the browser at 2026-09-04 23:5x. The two properties are
     * SEPARATE layers and both have to be reset.
     *
     * The contrast figure recorded for this state was also wrong while the
     * gradient survived: it was computed against the transparent colour rather
     * than against what was actually painted. Any future measurement of a
     * vendor state must confirm the fill is the one WE set, not merely that our
     * declaration is present. Same for text-shadow, which the library uses to
     * emboss the numeral against its own gradient and which reads as a smudge
     * once the gradient is gone. */
    background-image: none;
    text-shadow: none;
    box-shadow: inset 0 0 0 var(--fx-border-width) var(--fx-color-indicator);
}

/* THE CHOSEN DAY. The one brand FILL in the panel — see the accent note. Both of
 * the library's names for it are covered: `active` is the day the picker holds,
 * `selected` is the same idea in its range mode. Placed AFTER today and at the
 * same weight, so today-that-is-also-chosen reads as chosen; that ordering is
 * the rule rather than an accident, because "what is set" outranks "what day it
 * is" on a form the user is filling in.
 *
 * MEASURED on the raised surface: the on-primary ink is 7.38:1 on the fill in
 * light and 5.16:1 in dark; the fill is 8.27:1 against the panel in light and
 * 2.94:1 in dark. That last figure is a hair under the 3:1 SC 1.4.11 asks of a
 * state boundary and it is the same figure the selected dropdown option carries,
 * recorded in both places rather than patched in one. It is not invisible — the
 * ink inside it is the strongest contrast in the panel — and the token behind it
 * is being moved this week by the palette work, so the honest move is to record
 * the number and re-measure after. */
.datepicker.datepicker.datepicker table tr td.active.active.active,
.datepicker.datepicker.datepicker table tr td.selected.selected.selected,
.datepicker.datepicker.datepicker table tr td span.active.active.active {
    color: var(--fx-color-text-on-primary);
    background-color: var(--fx-color-primary);
    background-image: none;
    box-shadow: none;
    text-shadow: none;
}

@media (any-hover: hover) {
    .datepicker.datepicker.datepicker table tr td.active.active.active:hover,
    .datepicker.datepicker.datepicker table tr td.selected.selected.selected:hover,
    .datepicker.datepicker.datepicker table tr td span.active.active.active:hover {
        background-color: var(--fx-color-primary-hover);
    }
}

/* A DAY OUTSIDE THE ALLOWED RANGE. frihat-date-field.js `linkRange` greys out
 * the impossible half of a from/to pair, so this is a real state on this
 * platform rather than a library feature nobody reaches. LAST IN THE SECTION AND
 * AT THE SAME WEIGHT AS THE CHOSEN DAY, so a day that is both never paints as
 * chosen. (0,6,3) and (0,6,4). */
.datepicker.datepicker.datepicker table tr td.disabled.disabled.disabled,
.datepicker.datepicker.datepicker table tr td span.disabled.disabled.disabled {
    color: var(--fx-color-disabled-fg);
    background-color: transparent;
    background-image: none;
    box-shadow: none;
    text-shadow: none;
    cursor: default;
}

/* FORCED COLOURS. The selected day is the only cell whose meaning is carried by
 * a fill, so it is the only one that needs restating when the system replaces
 * every colour. The selector is repeated IDENTICALLY: a media query adds no
 * specificity, so this arm wins on source order alone, and writing it any
 * shorter would have made it silently inert. */
@media (forced-colors: active) {
    .datepicker.datepicker.datepicker table tr td.active.active.active,
    .datepicker.datepicker.datepicker table tr td.selected.selected.selected,
    .datepicker.datepicker.datepicker table tr td span.active.active.active {
        color: HighlightText;
        background-color: Highlight;
        forced-color-adjust: none;
    }

    .datepicker.datepicker.datepicker table tr td.today.today.today,
    .datepicker.datepicker.datepicker table tr td span.today.today.today {
        box-shadow: none;
        outline: var(--fx-border-width) solid CanvasText;
        outline-offset: calc(-1 * var(--fx-border-width));
    }
}


/* 10.3 Search.
 *
 * THE NATIVE CANCEL BUTTON IS SUPPRESSED. RULED 2026-08-03, after two earlier
 * passes left it open. It is a real decision with a real cost, so the reasoning
 * is recorded rather than just the outcome.
 *
 * WHAT WAS HERE: Blink and WebKit expose `::-webkit-search-cancel-button`, and
 * this file redrew it with a masked data-URI cross sized at `fx-icon-sm` â€” 14px
 * fine, 16px coarse. That is UNDER the 24px SC 2.5.8 Target Size (Minimum)
 * floor, and every other interactive control in this file is explicitly floored
 * by a `max()` against a control token.
 *
 * THE EXEMPTION WE WOULD HAVE BEEN RELYING ON DOES NOT HOLD. SC 2.5.8's "User
 * agent control" exception covers a target "determined by the user agent and NOT
 * MODIFIED by the author". We set `appearance: none`, both dimensions, a margin,
 * a mask and a colour â€” the exception is forfeit the moment the first of those
 * is written, and arguing otherwise is arguing that restyling a control is not
 * modifying it. The other two candidate exceptions fail as well: SPACING cannot
 * apply, because the 24px circle around the clear button necessarily intersects
 * the field's own target area; and EQUIVALENT needs a second control on the page
 * performing the same function, which no page here provides.
 *
 * SO THE CONFORMANT STATES ARE A 24px TARGET OR NO TARGET, AND 24 CANNOT BE
 * GUARANTEED. A previous pass declined to grow it for a reason that is still
 * correct: the smallest sanctioned size steps cannot carry it. `.fx-control-xs`
 * is 24px tall with 4px block padding, so its content box is 16px; the grid step
 * in 1c is 28px with the same padding, so 20px. A 24px pseudo-element inside
 * either bleeds past the field's own rounded edge. Growing only the BOX while
 * holding the glyph at 14px through `mask-size` does not rescue it â€” the target
 * IS the box, and the box is what overflows. A control that conforms on three
 * rungs of the ladder and overflows on two is the "half migrated field" that
 * section Z names as a worse outcome than losing outright.
 *
 * SO IT IS HIDDEN, AND `.fx-input-action` IS THE ANSWER. That class is floored
 * on BOTH axes â€” `min-block-size: fx-control-h-xs` plus an inline `max()`, see
 * the SC 2.5.8 note in section 11 â€” and it carries a real focus ring, which a UA
 * pseudo-element cannot be given at all. This is not a new recommendation: the
 * prose being replaced here already said "pages that need one in every engine
 * should render a real button and use .fx-input-action". Hiding the native one
 * makes that the ONLY route rather than the fallback route.
 *
 * AND IT MAKES THE ENGINES AGREE. Gecko exposes no equivalent pseudo-element, so
 * Firefox has never shown a clear affordance here. The state being removed is
 * therefore "an undersized clear button in Chrome and Edge, nothing in Firefox"
 * â€” which is the worst of both, an inconsistent affordance that also misses the
 * target-size floor. After this the control is absent in every engine and the
 * platform has one answer for clearing a search field.
 *
 * THE COST, STATED PLAINLY: a search box that wants a visible clear control must
 * now render one. `appearance: none` STAYS, or the UA button comes back.
 * The caret and the placeholder tier for this field are set in section 3. */
input[type="search"] {
    /* The magnifier hint belongs on an input group addon, not on the control,
     * so screen readers are not told about a decorative glyph. */
    padding-inline-end: var(--fx-ctl-pad-x);
}

input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
    display: none;
}

/* 10.4 File. The native button is redrawn through the Bootstrap and WebKit
 * pseudo elements so it reads as a secondary action attached to the field.
 * Real buttons remain 04-buttons' territory; this is the control's own chrome. */
/* A FILE INPUT IS NOT IN SECTION 1's LIST â€” it is a replaced element with a
 * generated button inside it, and section Z's focus rule excludes it by name â€”
 * so like the combobox trigger it declares its own local set and then reads it.
 * It used to name fx-color-field-bg, fx-radius-md, fx-shadow-well and
 * fx-control-h-lg directly, which is the same defect one level down: a page
 * could not put a file field on a size step, and the trigger inside it could
 * not follow one. Its own padding is zero because the generated button owns the
 * inline gutter, so the pad locals are set to zero rather than left at the
 * default and then overridden by a literal. */
input[type="file"],
.form-control[type="file"] {
    --fx-ctl-h: var(--fx-control-h-lg);
    --fx-ctl-pad-x: 0;
    --fx-ctl-pad-y: 0;
    --fx-ctl-radius: var(--fx-radius-md);
    --fx-ctl-font-size: var(--fx-text-sm);
    --fx-ctl-bg: var(--fx-color-field-bg);
    --fx-ctl-fg: var(--fx-color-text);
    --fx-ctl-border: 0;
    --fx-ctl-shadow: var(--fx-shadow-well);

    display: flex;
    align-items: center;
    inline-size: 100%;
    min-block-size: var(--fx-ctl-h);
    padding-inline: var(--fx-ctl-pad-x);
    padding-block: var(--fx-ctl-pad-y);
    color: var(--fx-ctl-fg);
    background-color: var(--fx-ctl-bg);
    border: var(--fx-ctl-border);
    border-radius: var(--fx-ctl-radius);
    box-shadow: var(--fx-ctl-shadow);
    cursor: pointer;
    overflow: hidden;
    transition: background-color var(--fx-dur-fast) var(--fx-ease-standard);
}

/* A file input is a FIELD and takes the field treatment, not the dark ring.
 * It is excluded from section 2's selector list (it carries no fx-ctl-* locals
 * of its own there) which is exactly why it had to be restated here and why it
 * was missed when the glow landed. */
input[type="file"]:focus-visible {
    --fx-ctl-bg: var(--fx-color-field-bg-focus);
    outline: var(--fx-focus-width) solid transparent;
    outline-offset: var(--fx-focus-offset);
    box-shadow: var(--fx-shadow-field-focus), var(--fx-ctl-shadow);
}

/* The trigger is told apart from the field by its FILL, not by a rule between
 * them: a sunken step against the field well. On hover it takes the NEUTRAL
 * wash, which is the same language the input group addons speak in section 11 â€”
 * it used to take a brand tint, which 00-tokens 3.9 does not sanction. */
input[type="file"]::file-selector-button {
    block-size: 100%;
    /* Reads the field's own locals, so a file field on a size step takes its
     * trigger with it instead of keeping a 40px button inside a 28px box. A
     * pseudo-element inherits custom properties from its originating element,
     * which is what makes this work at all. The trigger supplies the inline
     * gutter the field itself set to zero, so it reads the pad-x of the STEP
     * rather than the field's own zeroed local. */
    min-block-size: var(--fx-ctl-h);
    margin-inline-end: var(--fx-space-3);
    padding-inline: var(--fx-control-pad-x-sm);
    font-family: inherit;
    font-size: var(--fx-ctl-font-size);
    font-weight: var(--fx-weight-medium);
    letter-spacing: var(--fx-tracking-ui);
    color: var(--fx-color-text-muted);
    background-color: var(--fx-color-surface-sunken);
    border: 0;
    cursor: pointer;
    transition:
        background-color var(--fx-dur-fast) var(--fx-ease-standard),
        color var(--fx-dur-fast) var(--fx-ease-standard);
}

@media (any-hover: hover) {
    input[type="file"]:hover::file-selector-button {
        background-color: var(--fx-color-active);
        color: var(--fx-color-text);
    }
}

input[type="file"]:disabled::file-selector-button {
    color: var(--fx-color-disabled-fg);
    background-color: var(--fx-color-disabled-bg);
    cursor: not-allowed;
}

/* The disabled FIELD, so the filename text beside the trigger dims with it.
 * Section 2's disabled rule reaches this element and sets fx-ctl-fg and
 * fx-ctl-bg, but at (0,1,1) against this section's (0,1,1) declarations â€” and
 * this section is later in the file, so it would have won and the field would
 * have stayed lit. Restated here, after the rule that caused it. */
input[type="file"]:disabled {
    --fx-ctl-fg: var(--fx-color-disabled-fg);
    --fx-ctl-bg: var(--fx-color-disabled-bg);
    --fx-ctl-shadow: none;
    cursor: not-allowed;
}

/* Drop zone variant for the case document uploader. */
.fx-file-drop {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--fx-space-2);
    min-block-size: calc(var(--fx-control-h-lg) * 2.5);
    padding: var(--fx-surface-pad-md);
    text-align: center;
    color: var(--fx-color-text-subtle);
    /* The dashed rule is gone. A drop target is a deeply RECESSED well â€” doubled
     * fx-shadow-well â€” which reads as "put something in here" without a single
     * stroke, and the fill difference against the page carries the
     * identification. */
    background-color: var(--fx-color-surface-sunken);
    border: 0;
    border-radius: var(--fx-radius-lg);
    box-shadow: var(--fx-shadow-well), var(--fx-shadow-well);
    cursor: pointer;
    transition:
        background-color var(--fx-dur-fast) var(--fx-ease-standard),
        box-shadow var(--fx-dur-fast) var(--fx-ease-standard),
        color var(--fx-dur-fast) var(--fx-ease-standard);
}

/* NEUTRAL, not brand: a drop zone under the cursor is a hovered row by another
 * name, and 00-tokens 3.9 names that explicitly as a grey wash. */
@media (any-hover: hover) {
    .fx-file-drop:hover {
        color: var(--fx-color-text);
        background-color: var(--fx-color-hover);
    }
}

.fx-file-drop:focus-within {
    color: var(--fx-color-text);
    background-color: var(--fx-color-hover);
}

/* The zone is a container, so the indicator lands on the container the user
 * reached — the file input inside it does not add a second one. It takes the
 * field glow like every other place you put data into; the outline stays
 * declared and transparent for forced-colours. */
.fx-file-drop:focus-within {
    outline: var(--fx-focus-width) solid transparent;
    outline-offset: var(--fx-focus-offset);
    box-shadow: var(--fx-shadow-field-focus);
}

/* The inner input surrenders BOTH indicators to the zone: `outline: none` alone
 * was enough while focus was an outline, but the glow is a box-shadow and the
 * input would now draw its own inside the zone's. */
.fx-file-drop input[type="file"]:focus-visible {
    outline: none;
    box-shadow: none;
}

/* A file actually hovering over the zone is the loudest state in the form: the
 * recess INVERTS into a raised, floating surface, so the zone visibly comes up
 * to meet the file. Still neutral â€” the elevation change is the signal. */
.fx-file-drop.is-dragover {
    color: var(--fx-color-text);
    background-color: var(--fx-color-level-3);
    box-shadow: var(--fx-shadow-float-md);
}

/* 10.5 Colour. Outside section 1's list for the same reason as the file input,
 * so it declares its own locals and reads them. The INLINE size is a swatch
 * proportion rather than a field width â€” one step wider than it is tall â€” so it
 * is derived from the height local instead of naming a second token, and a
 * colour picker on a size step now keeps that proportion at every rung. */
input[type="color"],
.form-control-color {
    --fx-ctl-h: var(--fx-control-h-lg);
    --fx-ctl-pad-y: var(--fx-space-1);
    --fx-ctl-radius: var(--fx-radius-md);
    --fx-ctl-bg: var(--fx-color-field-bg);
    --fx-ctl-border: 0;
    --fx-ctl-shadow: var(--fx-shadow-well);

    inline-size: calc(var(--fx-ctl-h) + var(--fx-space-1));
    min-inline-size: calc(var(--fx-ctl-h) + var(--fx-space-1));
    block-size: var(--fx-ctl-h);
    min-block-size: var(--fx-ctl-h);
    padding: var(--fx-ctl-pad-y);
    cursor: pointer;
    background-color: var(--fx-ctl-bg);
    border: var(--fx-ctl-border);
    border-radius: var(--fx-ctl-radius);
    box-shadow: var(--fx-ctl-shadow);
}

input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
input[type="color"]::-webkit-color-swatch {
    border: 0;
    border-radius: var(--fx-radius-xs);
}
input[type="color"]::-moz-color-swatch {
    border: 0;
    border-radius: var(--fx-radius-xs);
}

/* 10.6 Range. Track and thumb are drawn per engine; both branches read tokens.
 *
 * THE THUMB IS NOT BRAND. It used to be fx-color-primary, which is a seventh
 * accent site and 00-tokens 3.9 does not grant one. It is now fx-color-text â€”
 * the same answer the reference gives for an active tab indicator, and the one
 * that surprises everybody. Measured against the rail fill it is 15.6:1 light
 * and 12.3:1 dark, so the 3:1 obligation is met with an order of magnitude to
 * spare and the slider still reads as the most definite thing in the row. */
input[type="range"],
.form-range {
    /* The thumb is the target, and fx-icon-md (16px fine) is UNDER the 24px
     * SC 2.5.8 floor â€” a slider handle is a real hit target, not a glyph. It is
     * therefore sized off the xs control step, which puts it at 24px fine /
     * 28px coarse and tiers it without a pointer query. */
    --fx-range-thumb: var(--fx-control-h-xs);

    inline-size: 100%;
    block-size: var(--fx-control-h-md);
    padding: 0;
    background: transparent;
    border: 0;
    box-shadow: none;
    appearance: none;
    cursor: pointer;
}

input[type="range"]:focus-visible,
.form-range:focus-visible {
    outline: var(--fx-focus-width) solid var(--fx-color-focus-ring);
    outline-offset: var(--fx-focus-offset);
    border-radius: var(--fx-radius-pill);
}

/* The rail is a recessed groove and the thumb FLOATS above it. That contrast of
 * depth is what separates the two now that neither carries a stroke. The rail is
 * one of the two shapes in this file that is DELIBERATELY a pill. */
input[type="range"]::-webkit-slider-runnable-track,
.form-range::-webkit-slider-runnable-track {
    block-size: var(--fx-space-2);
    background-color: var(--fx-color-field-bg);
    border: 0;
    border-radius: var(--fx-radius-pill);
    box-shadow: var(--fx-shadow-well);
}

input[type="range"]::-webkit-slider-thumb,
.form-range::-webkit-slider-thumb {
    appearance: none;
    inline-size: var(--fx-range-thumb);
    block-size: var(--fx-range-thumb);
    margin-block-start: calc((var(--fx-range-thumb) - var(--fx-space-2)) / -2);
    background-color: var(--fx-color-text);
    border: 0;
    border-radius: var(--fx-radius-circle);
    box-shadow: var(--fx-shadow-float-sm);
    transition: transform var(--fx-dur-fast) var(--fx-ease-standard);
}

input[type="range"]:active::-webkit-slider-thumb,
.form-range:active::-webkit-slider-thumb { transform: scale(var(--fx-press-scale)); }

input[type="range"]::-moz-range-track,
.form-range::-moz-range-track {
    block-size: var(--fx-space-2);
    background-color: var(--fx-color-field-bg);
    border: 0;
    border-radius: var(--fx-radius-pill);
    box-shadow: var(--fx-shadow-well);
}

input[type="range"]::-moz-range-thumb,
.form-range::-moz-range-thumb {
    inline-size: var(--fx-range-thumb);
    block-size: var(--fx-range-thumb);
    background-color: var(--fx-color-text);
    border: 0;
    border-radius: var(--fx-radius-circle);
    box-shadow: var(--fx-shadow-float-sm);
}


/* â”€â”€ 11) Input groups â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * Bootstrap flattens the joined corners with PHYSICAL border radius shorthands,
 * which produces visibly wrong corners in RTL. We neutralise the shorthand and
 * restate every corner with logical properties, so the group is correct in both
 * directions with a single rule set.
 *
 * NO SEAMS. The members used to be separated by a shared hairline and a negative
 * margin that collapsed it. Both are gone: the GROUP is the well now, its
 * members are transparent, and an addon is told apart from the field purely by
 * sitting one fill step darker.
 *
 * THIS IS THE ONE COMPONENT IN THE FILE THAT CANNOT TAKE AN OUTLINE, and it is
 * why fx-shadow-focus exists. The group must keep overflow: hidden to hold its
 * members' fills inside the assembly's own corners, and an outline at a positive
 * offset would be clipped by exactly that. So the group's focus indicator is the
 * flat compatibility ring â€” fx-shadow-focus, a solid 2px box-shadow in the same
 * fx-color-focus-ring at the same width, no blur and no spread â€” which is the
 * only sanctioned box-shadow expression of focus in the system. The individual
 * member surrenders its own outline so the ring surrounds the whole assembly.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* THE GROUP IS THE FIELD, so it declares the field's locals â€” and this is the
 * one place in the file where a WRAPPER legitimately owns them. The members
 * that are real controls re-set their own copies from section 1 the moment the
 * cascade reaches them, which is correct and harmless because the two agree;
 * the members that are NOT controls (the addons, the trailing action) have no
 * copy of their own and read the group's, which is how they stay the same
 * height and the same inline gutter as the field they are welded to.
 *
 * A page puts an input group on a size step by declaring the locals on the
 * GROUP and on its controls together, e.g.
 * `.input-group.fx-control-md, .input-group.fx-control-md > :is(input, select)`. */
.input-group {
    --fx-ctl-h: var(--fx-control-h-lg);
    --fx-ctl-pad-x: var(--fx-control-pad-x-sm);
    --fx-ctl-radius: var(--fx-radius-md);
    --fx-ctl-bg: var(--fx-color-field-bg);
    --fx-ctl-shadow: var(--fx-shadow-well);

    display: flex;
    flex-wrap: wrap;   /* wraps rather than overflowing a narrow card */
    align-items: stretch;
    inline-size: 100%;
    min-inline-size: 0;
    background-color: var(--fx-ctl-bg);
    border-radius: var(--fx-ctl-radius);
    box-shadow: var(--fx-ctl-shadow);
    /* overflow keeps every member's fill inside the assembly's own corners, so
     * no child has to restate them and RTL cannot get them wrong. */
    overflow: hidden;
    transition:
        background-color var(--fx-dur-fast) var(--fx-ease-standard),
        box-shadow var(--fx-dur-fast) var(--fx-ease-standard);
}

/* The control claims the row and only yields when it can no longer hold a
 * readable measure, at which point the addons wrap onto their own line.
 * The member is a transparent window onto the group's own fill.
 *
 * â•â• THE SURRENDER PAINTS, IT DOES NOT ONLY SET THE LOCAL â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * ADDED 2026-08-03, after the local alone was measured failing in a modal. The
 * three rules in this section that hand the fill back to the group each set
 * `--fx-ctl-bg: transparent` and then relied on section 1's
 * `background-color: var(--fx-ctl-bg)` to do the painting. That works only for
 * as long as nothing else paints the fill DIRECTLY at a heavier weight, and
 * something does: 01-base states the hover and focus fills as literal
 * `background-color` declarations rather than through this file's locals â€”
 *     :hover        input:not([â€¦]):hover:not(:disabled)   (0,3,1)
 *     :focus        input:not([â€¦]):focus-visible          (0,2,1)
 * against section 1's paint at (0,1,1). At REST the two are level and source
 * order settles it our way, which is why the resting member was always correct
 * and the fault only appeared in a state.
 *
 * WHY IT LOOKED FIXED. Section Z restates the same paint at (0,5,0) and (0,3,0)
 * reading fx-ctl-bg, so INSIDE the app shell the local reached the pixels after
 * all and the member stayed transparent. Every ABP MODAL is appended to `body`,
 * outside `.lpx-content`, so section Z never runs there â€” and that is where it
 * was measured, on the new-user dialog: the group correctly took the hover fill
 * AND the member painted the same colour opaquely on top of the group's well,
 * with the resolved local sitting at `transparent` the whole time. A defect
 * visible only outside the theme scope is precisely the shape section Z.1
 * warns about, arriving from the other direction.
 *
 * So each rule now states the paint as well as the local. Both halves read
 * fx-ctl-bg, so nothing is duplicated and a consumer that retunes the fill
 * still moves both. */
.input-group > :is(.form-control, .form-select, input, select, textarea) {
    position: relative;
    flex: 1 1 min(100%, 12ch);
    inline-size: 1%;
    min-inline-size: 0;
    --fx-ctl-bg: transparent;
    --fx-ctl-shadow: none;
    background-color: var(--fx-ctl-bg);
}

/* â”€â”€ 11.0a) HOVER BELONGS TO THE ASSEMBLY, EXACTLY AS FOCUS ALREADY DOES â”€â”€â”€â”€â”€
 *
 * THE DEFECT, MEASURED ON /Account/Manage AND ON THE NEW-USER MODAL, 2026-08-03.
 * Hovering a password field painted the INPUT opaque:
 *     .input-group       background-color  rgb(247, 251, 245)  plus the well
 *     input.form-control background-color  rgb(251, 253, 249)  no shadow at all
 * An opaque member with no depth of its own, sitting inside a sunken assembly,
 * covers the group's inset well across exactly the part of the assembly the
 * pointer is over. That is the SAME fault section 11.1 had just fixed one member
 * along â€” the reveal button painting over the well â€” recurring on the field
 * itself, and it is a conformance loss rather than an untidiness: fx-shadow-well
 * is this control's only SC 1.4.11 identification cue, and hover is the state a
 * pointer user is in whenever they are about to type.
 *
 * WHY THE MEMBER WON. Section 11's surrender rule is
 *     .input-group > :is(.form-control, â€¦)                       (0,2,0)
 * and section 2's hover rule computes as
 *     :is(.form-control, â€¦):hover:not(:disabled):not([readonly])  (0,4,0)
 * because :is() and each :not() contribute the weight of their most specific
 * argument. Section 11 anticipated this for FOCUS and wrote a (0,3,0) rule to
 * answer it; it never wrote the hover twin, so the one state it did not name is
 * the one state the member escaped through. Nothing had changed in either
 * section â€” the collision was there from the day the group took over the well.
 *
 * THE FIX IS TWO RULES, AND IT IS THE FOCUS MODEL COPIED VERBATIM.
 *   1. THE GROUP takes the hover fill, through the local, exactly as
 *      :focus-within takes the focus fill. Until now an input group was the one
 *      field on the platform that did not answer the pointer at all, which is a
 *      second defect the first one was hiding: with the member painting, SOME
 *      lightening happened, so the assembly looked responsive while what was
 *      actually responding was a slab over half of it.
 *   2. THE MEMBER surrenders the hover fill, so it stays a transparent window on
 *      the group's own well.
 *
 * SPECIFICITY, BOTH HALVES:
 *   The group rule is (0,2,0) and is placed BEFORE `.input-group:focus-within`,
 *   which is also (0,2,0). Source order therefore settles the tie in FOCUS's
 *   favour, which is the order this system wants: a field the user has entered
 *   outranks a field the pointer is merely crossing. Moving either rule past the
 *   other silently inverts that, so they must stay in this order.
 *
 *   The member rule mirrors section 2's guard list exactly and lands at (0,5,0),
 *   one step over the (0,4,0) it has to answer. The two :not() arms are not
 *   decoration: without them the rule is (0,3,0) and LOSES, which is the whole
 *   mechanism of the defect. Matching the guards also means this rule neutralises
 *   precisely the rule that fires and nothing else â€” a disabled or readonly
 *   member never reaches section 2's hover rule in the first place and still
 *   takes its transparency from the plain surrender rule above.
 *
 * Section Z needs no twin. Its `.lpx-content .form-control:hoverâ€¦` restates
 * `background-color` off fx-ctl-bg and reads the local, so fixing the local
 * fixes the hardened copy in the same stroke. The print tier DOES need one, and
 * section 17 carries it beside the :focus-within entry that is there for the
 * identical reason. */
@media (any-hover: hover) {
    .input-group:hover {
        --fx-ctl-bg: var(--fx-color-field-bg-hover);
    }

    /* (0,5,0). It has to clear TWO rules, not one: section 2's local at (0,4,1),
       and 01-base's literal hover paint at (0,3,1) â€” see the note over the base
       surrender rule for why the paint is restated here at all. */
    .input-group > :is(.form-control, .form-select, input, select, textarea):hover:not(:disabled):not([readonly]) {
        --fx-ctl-bg: transparent;
        --fx-ctl-shadow: none;
        background-color: var(--fx-ctl-bg);
    }
}

/* An addon is identified by ONE fill step, not by a rule. It sits on the sunken
 * surface while the field sits on the field fill, and the step between the two
 * is the seam. */
.input-group-text,
.fx-input-addon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--fx-space-1);
    /* Both read the GROUP's locals, so an addon can never be a different height
     * or sit on a different gutter from the field it is welded to. */
    min-block-size: var(--fx-ctl-h);
    padding-inline: var(--fx-ctl-pad-x);
    /* NOT fx-ctl-font-size, and deliberately so. An addon is CHROME attached to
     * a field, not the value inside it, and the house rule puts chrome one tier
     * under the content it names â€” an addon set at the field's own size reads as
     * a second value competing with the first. */
    font-size: var(--fx-text-sm);
    letter-spacing: var(--fx-tracking-ui);
    white-space: nowrap;
    color: var(--fx-color-text-subtle);
    background-color: var(--fx-color-surface-sunken);
    border: 0;
    transition:
        background-color var(--fx-dur-fast) var(--fx-ease-standard),
        color var(--fx-dur-fast) var(--fx-ease-standard);
}

/* Every member is square: the GROUP clips the assembly's corners, so no child
 * needs a logical corner of its own and RTL has nothing left to get wrong. */
.input-group > * {
    border-radius: 0;
}

/* Group level focus â€” see the note above for why this is a box-shadow and not
 * an outline. The well is listed SECOND so the ring paints on top of it, and the
 * well survives, so the assembly is still identifiable as a field while focused. */
.input-group:focus-within {
    /* The fill moves through the local, exactly as a lone field's does in
     * section 2, so the two states are one decision. The RING is a literal
     * because it is not the control's depth: fx-shadow-focus is the flat
     * compatibility ring this one component is entitled to, and it is listed
     * FIRST so it paints on top of the well. The well half reads the local, so
     * a consumer that retunes the depth keeps it while focused. */
    --fx-ctl-bg: var(--fx-color-field-bg-focus);

    /* THE RING IS THE FIELD GLOW SINCE 2026-08-29, not fx-shadow-focus. An
     * input group IS a field â€” it is the reason the owner's objection to the
     * detached ring applies here too â€” and leaving it on the old compatibility
     * ring would have made the one assembled field on a form look unlike the
     * seven plain ones beside it.
     *
     * THE GAP LAYER GOES WITH IT, and its whole failure mode goes with it: the
     * old ring painted a 2px gap in fx-shadow-focus-surface and therefore had to
     * be told which plane the assembly was sitting on. The glow starts at the
     * border box, so there is no gap to paint and nothing to get wrong when this
     * component is used inside a popover.
     *
     * The well is still listed SECOND so it survives, exactly as before. */
    box-shadow: var(--fx-shadow-field-focus), var(--fx-ctl-shadow);
}

/* The focused MEMBER surrenders its own indicator: the assembly carries it, and
 * two concentric rings 1px apart read as a rendering fault.
 *
 * â•â• THE CLASS IS DOUBLED, AND UNTIL 2026-08-03 IT WAS NOT â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * THE DEFECT, SEEN ON /Account/Manage AND IN THE NEW-USER MODAL. Focusing a
 * password field painted a 2px BRAND-GREEN VERTICAL BAR down the seam between
 * the field and its reveal toggle. Measured on the focused input:
 *     outline   rgb(20, 90, 50) solid 2px      â† this rule says `none`
 *
 * WHY IT LOST. The declaration above is exactly (0,3,0):
 *     `.input-group` 1 class + `:is(â€¦)` 1 class + `:focus-visible` 1 pseudo.
 * Section Z's outline restatement is ALSO exactly (0,3,0):
 *     `.lpx-content` 1 class + `.form-control` 1 class + `:focus-visible`.
 * A tie is settled by source order, section Z is two thousand lines later, and
 * so the member took the ring back on every page rendered inside the app shell,
 * which is every page. Nothing was wrong with either rule read on its own; the
 * two simply arrived at the same weight, which is the failure mode section 1b
 * records as the hardest kind to see and the reason it doubles its own classes.
 *
 * WHY THE BAR IS VISIBLE AT ALL, given the group clips its overflow. The ring is
 * drawn at a POSITIVE 2px offset, so it traces a rectangle 2px outside the
 * input's box on all four sides. Three of those sides fall outside the assembly
 * and `overflow: hidden` eats them â€” which is why this read as a single stray
 * line rather than as a second rectangle, and why it survived review. The fourth
 * side is the edge the input SHARES with the button, and that edge is INSIDE the
 * group, so nothing clips it. The result is a green bar welded across the seam,
 * on top of the reveal toggle, present on the field's focus and absent on the
 * button's â€” the exact "rendering fault" reading this rule exists to prevent.
 *
 * THE FIX IS CLASS DOUBLING, NOT A SECTION Z RESTORE. Section Z.1 puts its two
 * restores inside the hardening block because they belong to ACCESSIBILITY TIERS
 * â€” forced colours and print â€” and scoping a tier to a theme class would silently
 * drop a field rendered outside the shell out of it. That argument does not reach
 * this rule: it is a plain component rule, it must win in and out of the shell
 * alike, and doubling takes it to (0,4,0) universally. Same idiom as the size
 * ladder in 1b and the button claim in 11.1, for the same reason.
 *
 * THE INDICATOR IS NOT LOST, and that was verified rather than assumed before
 * this was changed. Measured on the focused assembly:
 *     .input-group  box-shadow  rgb(242,246,240) 0 0 0 2px,
 *                               rgb(20,90,50)    0 0 0 4px,  â† fx-shadow-focus
 *                               plus the three-layer well
 * `:focus-within` fires and the ring surrounds the WHOLE control, which is what
 * section 11 designed and what SC 2.4.7 is satisfied by here. */
.input-group.input-group > :is(.form-control, .form-select, input, select, textarea):focus,
.input-group.input-group > :is(.form-control, .form-select, input, select, textarea):focus-visible {
    z-index: 2;
    --fx-ctl-bg: transparent;
    --fx-ctl-shadow: none;
    /* (0,4,0), over 01-base's literal focus paint at (0,2,1). Outside the app
       shell nothing else was restating this, so a focused member in an ABP modal
       painted fx-color-field-bg-focus opaquely across the group's well. See the
       note over the base surrender rule. */
    background-color: var(--fx-ctl-bg);
    outline: none;
}

/* The addon promotes a text tier with the group. NEUTRAL â€” it used to take a
 * brand tint and a link colour, which 00-tokens 3.9 does not sanction. */
.input-group:focus-within > :is(.input-group-text, .fx-input-addon) {
    color: var(--fx-color-text);
    background-color: var(--fx-color-active);
}

/* An icon only trailing action inside the field, e.g. a reveal toggle. Its own
 * hit area is filled on hover rather than outlined.
 *
 * â•â• THE SC 2.5.8 GAP THIS CLOSES â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * The inline axis was floored at max(fx-control-h-lg, 1.5rem) and the BLOCK
 * axis was `block-size: auto`. Unfloored. Inside a wrapping `.input-group` the
 * members are stretched by `align-items: stretch` and the control kept the
 * assembly tall, so the rendered height looked fine and the defect was
 * invisible â€” but this class is not scoped to an input group, and the moment it
 * is used on its own (a reveal toggle beside a masked value in a detail row,
 * which is exactly what section 15 is built for) `auto` resolves to the glyph
 * plus nothing, and a 16px icon ships a 16px target. That is under the 24px
 * SC 2.5.8 minimum, and it was the one interactive control in this file not
 * floored by a max().
 *
 * A FLOOR, NOT A FIXED HEIGHT. `block-size: var(fx-ctl-h)` would have been the
 * obvious line and it is the wrong one twice over: it would stop the button
 * stretching with a wrapped or multi line group, and â€” since fx-ctl-h is
 * inherited from the group, which a page may put on the xs step â€” it could
 * itself resolve to 24px or, on a consumer's own scope, to something smaller.
 * min-block-size against fx-control-h-xs is a guarantee rather than a value:
 * 24px is the SC 2.5.8 boundary exactly, the coarse tier lifts it to 28px, and
 * `block-size: auto` stays so the control still stretches when its container
 * gives it room.
 *
 * THE CENTRING WAS ALREADY THERE and is what makes the floor safe: this is an
 * inline-flex box with align-items and justify-content both centre, so the
 * glyph sits in the middle of whatever height the floor produces rather than
 * being pinned to the block start. Verified against both cases â€” stretched
 * inside a group, and standalone at the 24px floor. */
.fx-input-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Square against the control height, never wider than the field is tall.
     * Reads the group's local, so the action tracks the size step. */
    inline-size: max(var(--fx-ctl-h, var(--fx-control-h-lg)), 1.5rem);
    min-inline-size: max(var(--fx-ctl-h, var(--fx-control-h-lg)), 1.5rem);
    block-size: auto;
    min-block-size: var(--fx-control-h-xs);
    color: var(--fx-color-text-subtle);
    background-color: transparent;
    border: 0;
    cursor: pointer;
    transition:
        color var(--fx-dur-fast) var(--fx-ease-standard),
        background-color var(--fx-dur-fast) var(--fx-ease-standard);
}

@media (any-hover: hover) {
    .fx-input-action:hover {
        color: var(--fx-color-text);
        background-color: var(--fx-color-hover);
    }
}

/* Inside the group's clipped box, so the ring is pulled inward by its own offset
 * rather than being cut off at the assembly edge. */
.fx-input-action:focus-visible {
    outline: var(--fx-focus-width) solid var(--fx-color-focus-ring);
    outline-offset: calc(var(--fx-focus-offset) * -1);
}


/* â”€â”€ 11.1) A REAL <button> INSIDE THE GROUP â€” the stock ABP case â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * THE DEFECT, MEASURED ON /Account/Manage, 2026-08-03.
 *
 * ABP's change-password form emits three input groups shaped
 *     <div class="input-group">
 *       <input type="password" class="form-control">
 *       <button class="btn btn-secondary password-visibility-button">
 * and NOTHING in this file reached that button. Section 11 hands the well to the
 * GROUP and makes the members transparent windows onto it, but its member rule
 * names `.form-control, .form-select, input, select, textarea` â€” a `.btn` is not
 * in the list, so the reveal toggle arrived as a fully dressed 04-buttons object
 * welded into the middle of a field. Measured:
 *     button background   fx-color-level-2 â€” the SAME fill as the field, opaque
 *     button box-shadow   the fx-btn-bevel â€” a 1px ring plus a drop shadow
 *
 * SO THE ASSEMBLY READ AS UNFINISHED, and this is the part worth stating
 * precisely because the first reading of it was wrong. The group's fill and its
 * fx-shadow-well were BOTH present and correct the whole time â€” verified on the
 * live page, the `.input-group` computed the full three-layer well. What the
 * audit measured was the INPUT's own `background: rgba(0,0,0,0)` and
 * `box-shadow: none`, which are not a defect at all: they are section 11's
 * design, the member deliberately surrendering its fill so the group can carry
 * one continuous well. The real fault is one level over: the BUTTON is opaque,
 * so it PAINTS OVER the group's inset well on its half of the assembly, and it
 * adds a RAISED bevel on top. A raised object sitting in a sunken well, masking
 * the well exactly where it sits. That is the visible seam, and that is why one
 * end of the control looked finished and the other did not.
 *
 * THE FIX IS THE ONE THIS FILE ALREADY WROTE FOR THIS EXACT CONTROL.
 * `.fx-input-action` is described a few rules up as "an icon only trailing
 * action inside the field, e.g. a reveal toggle" â€” the ABP button IS that
 * control, it simply arrives without the class and this platform does not own
 * the markup that emits it. So the treatment is routed to it by selector
 * instead: transparent, unbevelled, square against the group's own height, one
 * text tier under the value, and a hover wash rather than a fill.
 *
 * SCOPED TO THE NEUTRAL VARIANTS ON PURPOSE. A branded button genuinely welded
 * to a field â€” a green "Ø¨Ø­Ø«" submit on a search group â€” is a different object
 * and must keep its fill, so only `.btn-secondary`, `.btn-outline-secondary`,
 * `.btn-light` and ABP's own `.password-visibility-button` are claimed here.
 *
 * IT MOVES THE BOOTSTRAP LOCALS, NOT THE PROPERTIES. `.btn` resolves its own
 * fill from the bs-btn-bg custom property, so redeclaring that variable retunes
 * the button without this file ever contesting a `background-color` declaration
 * with 04-buttons. Same contract this file asks of its own consumers, one layer
 * over â€” and the same reason section 1 holds its geometry in locals.
 *
 * SPECIFICITY: the class is DOUBLED, exactly as the size ladder in section 1b
 * doubles its own. 04-buttons writes its variants as `.btn.btn-secondary` at
 * (0,2,0); a single-class rule here would tie and be settled only by file order,
 * which 1b already records as too fragile to stand on. Doubling takes these to
 * (0,3,0) and the question never arises. */
.input-group > .btn.btn {
    /* NO RAISED BEVEL INSIDE A SUNKEN ASSEMBLY. One dial, because 04-buttons
     * routes every variant's depth through this single local â€” so this neither
     * restates a shadow nor has to know what the variant chose. */
    --fx-btn-shadow: none;
}

.input-group > :is(.btn-secondary, .btn-outline-secondary, .btn-light, .password-visibility-button).btn {
    /* Transparent, so the GROUP's well runs unbroken beneath the whole assembly
     * â€” which is the entire point of section 11 and the one thing the button was
     * breaking. fx-shadow-well is the SC 1.4.11 carrier for this control; a
     * member that hides half of it is a conformance defect, not an untidiness. */
    --bs-btn-bg: transparent;
    --bs-btn-border-color: transparent;
    --bs-btn-hover-border-color: transparent;
    --bs-btn-active-border-color: transparent;
    /* The NEUTRAL wash, the same pair `.fx-input-action` and the input-group
     * addons already speak. No brand: an affordance is not one of this file's
     * two sanctioned accent sites. */
    --bs-btn-hover-bg: var(--fx-color-hover);
    --bs-btn-active-bg: var(--fx-color-active);
    /* One tier under the value it reveals â€” chrome attached to a field, never a
     * second value competing with the first. Section 11's addon rule makes the
     * same argument for the same reason. */
    --bs-btn-color: var(--fx-color-text-subtle);
    --bs-btn-hover-color: var(--fx-color-text);
    --bs-btn-active-color: var(--fx-color-text);
    /* Square against the field, never wider than the field is tall. The SAME
     * expression `.fx-input-action` uses, reading the GROUP's own local, so the
     * two controls cannot drift and both follow a size step. It was rendering
     * 52px wide against a 40px tall field. */
    --bs-btn-padding-x: 0;
    inline-size: max(var(--fx-ctl-h, var(--fx-control-h-lg)), 1.5rem);
    min-inline-size: max(var(--fx-ctl-h, var(--fx-control-h-lg)), 1.5rem);
}

/* â•â• THE FOCUS INDICATOR â€” THE ACCESSIBILITY HALF, AND THE TRUTH ABOUT IT â•â•â•
 *
 * THE SUSPICION WAS THAT THESE THREE PASSWORD FIELDS HAD NO FOCUS INDICATOR AT
 * ALL, on the reasoning that section 11 sets `outline: none` on a focused member
 * while the member's own box-shadow is none. IT IS NOT TRUE, and it was checked
 * rather than assumed. Measured on the live page, focusing `#CurrentPassword`:
 *     resting  .input-group  box-shadow: <the three-layer well>
 *     focused  .input-group  box-shadow: <2px page-colour halo>,
 *                                        <2px ring in fx-color-focus-ring>,
 *                                        <the three-layer well>
 * `.input-group:focus-within` fires and the assembly takes fx-shadow-focus
 * exactly as section 11 designed. The INPUT is conformant. Nothing to fix, and
 * the finding is recorded here so the next audit does not re-open it.
 *
 * WHAT IS REAL IS ONE STEP OVER, AND IT IS A GENUINE SC 2.4.7 FAILURE.
 * The BUTTON's own indicator is `outline` at a POSITIVE `outline-offset`,
 * inherited from 04-buttons â€” and it is drawn inside a container whose
 * `overflow: hidden` is load bearing and cannot be removed, because it is what
 * clips every member's fill into the assembly's corners. So the ring is CLIPPED
 * AWAY. Confirmed visually in both focus states: tabbing from the input to the
 * reveal toggle changed the rendering by a single hairline at the seam, because
 * the only thing still painting was the group's own `:focus-within` ring â€” which
 * was ALREADY on for the input and is identical for both. A keyboard user
 * cannot tell whether focus is in the password field or on the button that
 * reveals it. The indicator does not move.
 *
 * THE FIX IS THE NEGATIVE OFFSET `.fx-input-action` ALREADY CARRIES, for exactly
 * this reason and with exactly this comment beside it: the ring is pulled inward
 * so the clip cannot reach it, and it now hugs the button rather than the
 * assembly â€” so focus visibly MOVES from one to the other. Same values as
 * 01-base section 11, same values as `.fx-input-action`; if these ever disagree,
 * 01-base is right. */
.input-group > .btn:focus-visible {
    outline: var(--fx-focus-width) solid var(--fx-color-focus-ring);
    outline-offset: calc(var(--fx-focus-offset) * -1);
    /* Above the sibling member, so the ring is never overpainted by the field's
     * own fill at the seam they share. */
    z-index: 2;
}

/* Opt in stacking for phones. Each member becomes a full row.
 *
 * THIS IS THE ONE PLACE THE CLIPPING TRICK STOPS COVERING FOR US, and it is why
 * the radius has to be restated with real specificity rather than left at
 * `.input-group.fx-input-group-stack > *`. Everywhere else the group's
 * overflow: hidden clips the members' corners, so whatever Bootstrap sets on a
 * child is invisible and its PHYSICAL border-top-left-radius / -bottom-left
 * shorthands do no harm in RTL. Stacking has to turn that clipping off â€” a
 * clipped stack would shear the rounded corners off every row but the first â€”
 * and the moment it does, Bootstrap's own joined-corner rules become visible.
 * Those rules are specificity (0,4,0):
 *     .input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle)
 * which BEATS a (0,2,0) `.input-group.fx-input-group-stack > *`. The result in
 * Arabic is a stack whose corners are flattened on the wrong side of every row.
 * The selector below is (0,5,0) so it wins outright, and it names the corners
 * logically so there is nothing left to mirror. */
@media (max-width: 575.98px) {
    .input-group.fx-input-group-stack {
        overflow: visible;
    }

    .input-group.fx-input-group-stack > :is(.form-control, .form-select, .input-group-text, .fx-input-addon, input, select, textarea, button, .btn):not(.dropdown-menu),
    .input-group.fx-input-group-stack > * {
        inline-size: 100%;
        flex: 1 1 100%;
        margin-inline-start: 0;
        /* The group's own local, so a stacked group on a size step keeps the
         * corner that step chose rather than snapping back to 8px. */
        border-start-start-radius: var(--fx-ctl-radius);
        border-start-end-radius: var(--fx-ctl-radius);
        border-end-start-radius: var(--fx-ctl-radius);
        border-end-end-radius: var(--fx-ctl-radius);
    }

    .input-group.fx-input-group-stack > * + * {
        margin-block-start: var(--fx-space-2);
    }
}


/* â”€â”€ 12) Checkboxes, radios and switches â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * LINEAR DENSITY, WCAG TARGET SIZE. The reference draws a 16px tick box; SC
 * 2.5.8 requires a 24px target. Both are satisfied by the same technique the
 * component was always built on, with the gutter widened from 2px to 4px:
 * the ELEMENT is 24px and its ARTWORK is 16px. A transparent 4px border creates
 * the extra hit area, background-clip: padding-box keeps the fill inside the
 * padding box, and the well draws the visible edge. Result: a 24x24 hit target
 * that reads as the 16x16 control the reference draws beside 15px text.
 *
 * The checked fill and the switch track come from the brand token; the tick
 * and knob glyphs stay Bootstrap's own images, which keeps this file free of
 * colour literals and lets Bootstrap's dark block supply the light variants.
 *
 * THE ONE SANCTIONED BRAND FILL IN THIS FILE. 00-tokens 3.9 holds the closed
 * list of accent sites and a checked tick box is not literally one of them. It is granted here
 * as the one defensible extension, and the reasoning is on the record: a checked
 * selection control is not decoration and not a hover state â€” it is a control
 * REPORTING ITS OWN VALUE, which is the same job as site 2 (a filled badge that
 * is genuinely a status). Every other brand reference in this file has been
 * removed. If a reviewer counts the brand references in 05-forms.css they should
 * find exactly two: this fill, and the text caret in section 3.
 *
 * NO OUTLINED BOXES, AND THE PADDING-BOX RING IS NOT ONE. The 24px hit area
 * comes from the transparent border, which paints nothing and is therefore not
 * a stroke: it is spacing expressed in the only property that survives on a
 * replaced element. That much is unchanged. What changed is what draws the
 * EDGE â€” read the next block before touching either.
 *
 * â•â• THE UNCHECKED BOX HAD NO BOUNDARY. FIXED 2026-08-03. â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * MEASURED on the login form: an unchecked `.form-check-input` was fill #f7fbf5
 * on a white card, 1.046:1, with a transparent border, no outline, and the only
 * edge anywhere on it being the top of fx-shadow-well. The bottom carried the
 * well's white lip at roughly 1:1. SC 1.4.11 wants 3:1 for the visual
 * information that identifies a control; a consent checkbox on a legal
 * platform's sign-in form had none worth the name.
 *
 * THE THREE THINGS THAT COULD NOT MOVE, AND WHY THE ANSWER IS AN INSET RING:
 *   1. The transparent border is LOAD BEARING for SC 2.5.8. Colouring it would
 *      paint a 4px stroke and make a 16px control look 24px, which is a
 *      different defect, not a fix.
 *   2. The TICK IS BOOTSTRAP'S, a background image bound to
 *      `.form-check-input:checked`. Nothing here may disturb the appearance
 *      value that keeps it painting; forcing `appearance: none` onto the bare
 *      selectors was examined at length below and rejected.
 *   3. The element is 24px but the thing a user SEES is the 16px padding box.
 *      An edge drawn on the border box would ring empty space.
 * An INSET box-shadow with zero offset, zero blur and a 1px spread satisfies all
 * three at once, because an inset shadow is painted inside the PADDING BOX by
 * definition. It lands exactly on the 16px artwork, costs no layout, changes no
 * hit area, and composes into the same box-shadow list as the well.
 *
 * MEASURED AFTER, both themes, rendered pixels rather than composites:
 *     LIGHT   ring #7a8d7f   3.53:1 on white Â· 3.23:1 on the card Â· 3.38:1 on
 *             the fill inside it. The well's band 1 measures 3.01:1 underneath.
 *     DARK    ring #7a8d7f   4.51:1 on the card Â· 4.30:1 on the fill.
 * The control therefore now carries TWO conformant identification cues in light
 * and a strong one in dark, where before it carried a shadow and a hope.
 *
 * A CHECKED BOX DOES NOT TAKE THE RING and does not need it: its fill is
 * fx-color-primary, which measures 8.27:1 against a white card. The `:checked`
 * rule below replaces the whole shadow list with a float, which is what drops
 * the ring, and that is deliberate rather than incidental.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.form-check {
    display: flex;
    align-items: flex-start;
    gap: var(--fx-space-2);
    /* The checkbox already satisfies SC 2.5.8 on its own, so the ROW only needs
     * enough height to stay comfortable and to give the label a generous strip
     * to be clicked on. fx-control-h-md is 32px fine / 40px coarse, which meets
     * the touch floor through the token tier rather than through a pointer media
     * query here. */
    min-block-size: var(--fx-control-h-md);
    padding-inline-start: 0;   /* Bootstrap's physical indent, replaced by gap */
    margin-block-end: var(--fx-space-1);
    min-inline-size: 0;
}

.form-check-input,
input[type="checkbox"],
input[type="radio"] {
    /* â•â• ONE SELECTION-CONTROL SYSTEM â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
     * Radio, checkbox and switch are three silhouettes of ONE control, so every
     * number they share is declared once, here, on the selector all three match.
     * Each has its own geometry, which is exactly why they drift apart if the
     * numbers are written per component. They are:
     *
     *   ring weight   fx-check-gutter   4px, transparent, all three
     *   boundary      fx-check-ring     the 3:1 padding-box edge, all three
     *   depth         fx-shadow-well    identical inset, all three
     *   artwork       fx-check-art      70% of the padding box: tick, dot and,
     *                                    via the knob inset, the switch
     *   selected fill fx-color-primary  identical, all three
     *   focus         the shared outline, pulled in by the gutter â€” all three
     *   press         fx-press-scale    identical, all three
     *
     * Change one of these and you have changed the selection control, not one
     * widget. There is no per-control override of any of them below. */
    --fx-check-gutter: 4px;    /* transparent hit-area ring */
    --fx-check-art: 70%;       /* tick and dot artwork, share of the box */
    /* THE VISIBLE BOUNDARY, and the control's SC 1.4.11 carrier. An INSET
     * shadow paints inside the padding box, so this lands on the 16px artwork
     * rather than on the 24px hit box, and it consumes no layout at all. The
     * width is fx-border-width so section 16.3's promotion to 2px reaches it for
     * free; the colour is the token literally named for a 3:1 boundary. Held as
     * a local so the switch track in 12.1, which restates the whole shadow list
     * at a heavier weight, composes the identical edge instead of writing a
     * second copy of this decision. */
    --fx-check-ring: inset 0 0 0 var(--fx-border-width) var(--fx-color-border-strong);

    /* THE SIZE IS DERIVED FROM A TOKEN, NOT WRITTEN AS A LITERAL, so the coarse
     * pointer tier in 00-tokens.css moves it for free and this file writes no
     * pointer media query of its own. fx-control-h-xs is 24px fine / 28px
     * coarse, so:
     *     fine    24px element, 24 - (2 x 4px gutter) = 16px artwork
     *     coarse  28px element,                         20px artwork
     * The fine-pointer result is the reference's 16px control inside a 24px
     * SC 2.5.8 target, and it grows on touch by itself. */
    --fx-check-size: var(--fx-control-h-xs);

    flex: 0 0 auto;
    inline-size: var(--fx-check-size);
    block-size: var(--fx-check-size);
    min-inline-size: var(--fx-check-size);
    margin-block-start: calc((var(--fx-control-h-md) - var(--fx-check-size)) / 2);
    margin-inline-start: 0;
    padding: 0;
    background-color: var(--fx-color-field-bg);
    background-clip: padding-box;      /* fill stays inside the 16px artwork */
    background-origin: padding-box;
    /* Transparent, so it paints nothing: this is the extra hit area that lifts a
     * 16px control to a 24px SC 2.5.8 target, not a visible edge. */
    border: var(--fx-check-gutter) solid transparent;
    /* RING FIRST, WELL UNDER IT. Shadows paint in declaration order with the
     * first on top, and the ring is the boundary while the well is the depth
     * behind it â€” reversing the pair would let the well's band soften the very
     * edge the control is identified by. */
    box-shadow: var(--fx-check-ring), var(--fx-shadow-well);
    cursor: pointer;
    /* accent-color COVERS UN-CLASSED NATIVE CONTROLS, AND IT IS DOING MORE WORK
     * THAN IT LOOKS. DO NOT ADD `appearance: none` TO THIS RULE.
     *
     * MEASURED, 2026-08-03. A bare `input[type=checkbox]` or `input[type=radio]`
     * keeps `appearance: auto`, so Blink renders the OS widget and silently
     * discards most of this rule: border, border-radius and box-shadow all
     * computed to their initial values on the bare control while the identical
     * declarations applied normally to `.form-check-input`. Only inline-size,
     * block-size and accent-color survived. That is a browser rule about
     * replaced elements, not a specificity problem, and no selector fixes it.
     *
     * SO WHY NOT FORCE `appearance: none` AND WIN? Because the tick and the dot
     * are not ours. They are Bootstrap background images attached to
     * `.form-check-input:checked`, and a bare input never receives them.
     * Forcing the appearance off would give a checked bare checkbox a solid
     * brand-green square WITH NO TICK IN IT: the checked state would become
     * invisible, which is a WCAG failure traded for a cosmetic gain. Supplying
     * our own tick is not free either, since this file is required to hold no
     * colour literal and an inline SVG tick is a colour literal in a data URI.
     *
     * WHAT WE DO INSTEAD is let the native control stay native and TINT it, so
     * it reports its value in the platform's own green rather than in the
     * browser's blue. It is a different silhouette from `.form-check-input`,
     * and that is an accepted, bounded divergence: a native tick box still
     * reads unambiguously as a tick box.
     *
     * VERIFIED AT THE SAME TIME: the running product contains ZERO bare
     * checkboxes and radios. ABP, LeptonX and the module dialogs all emit
     * `.form-check-input`, so this path is a safety net and not the common case.
     * If a hand-built dialog ever ships bare selection controls in quantity, the
     * fix is to add the class in the markup, not to fight the engine here. */
    accent-color: var(--fx-color-primary);
    transition:
        background-color var(--fx-dur-fast) var(--fx-ease-standard),
        box-shadow var(--fx-dur-fast) var(--fx-ease-standard),
        transform var(--fx-dur-fast) var(--fx-ease-standard),
        background-size var(--fx-dur-base) var(--fx-ease-standard);
}

/* The press. A tick box that does not give under the pointer reads as a picture
 * of a tick box; fx-press-scale is the same compression every other control in
 * the system uses, so nothing here invents a second number. */
:is(.form-check-input, input[type="checkbox"], input[type="radio"]):active:not(:disabled) {
    transform: scale(var(--fx-press-scale));
}

/* Inside a .form-check the box is centred against the ROW rather than against a
 * standalone control height, so it lines up with the first line of the label â€”
 * which the label rule below pads to the same centre. Both halves derive from
 * fx-control-h-md, so the pair cannot drift when the token tier moves them on a
 * coarse pointer. In a dense inline filter row there is no row to centre in.
 *
 * â•â• THE INLINE MARGIN IS A CANCELLATION, AND IT WAS MISSING â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * THE DEFECT: the box hung 22.52px OUTSIDE its own content column, out of line
 * with the fields above it and the button below. Platform-wide, and worst on the
 * login form, which is the first screen anybody sees.
 *
 * WHY. Bootstrap indents the row and then pulls the control back out of it:
 *     .form-check              padding-left:  1.5em
 *     .form-check .form-check-input   margin-left: -1.5em   (0,2,0)
 * mirrored to `padding-right` / `margin-right` in the RTL build. The rule above
 * this one replaced the INDENT â€” `.form-check` sets `padding-inline-start: 0`
 * and spends the space as `gap` instead â€” but nothing ever cancelled the PULL.
 * Half of a two-part vendor idiom was removed and the other half left running,
 * so the negative margin dragged the control out of a column that no longer had
 * an indent to give back. 1.5em at the field's 15px is 22.5px, which is the
 * number that was measured.
 *
 * The base rule a few lines up does say `margin-inline-start: 0`, and it cannot
 * help: it matches `.form-check-input` at (0,1,0) and Bootstrap's is (0,2,0).
 * This rule is the one at matching weight, and it loads later, so the
 * cancellation belongs here and nowhere else.
 *
 * `margin-inline`, BOTH SIDES, NOT JUST THE START. The switch takes a SECOND
 * vendor pull of its own â€” `.form-switch .form-check-input { margin-left:
 * -2.5em }`, also (0,2,0), also mirrored in RTL â€” and `.form-switch` markup
 * carries `.form-check` too, so this selector reaches it. One logical shorthand
 * cancels both pulls in both directions and needs no RTL mirror of its own. A
 * `margin-inline-start` alone would have fixed the checkbox and left the switch
 * hanging 37.5px out, which is the same defect surviving in the one control
 * least likely to be re-tested.
 *
 * NOTHING ELSE WANTS AN INLINE MARGIN HERE. `.form-check` is a flex row whose
 * spacing is `gap`, so the control's own margins are not carrying any layout â€”
 * which is precisely why the leftover pull was pure damage. The float Bootstrap
 * sets alongside it needs no cancelling either: a float is inert on a flex item.
 */
.form-check .form-check-input {
    margin-block-start: max(0px, calc((var(--fx-control-h-md) - var(--fx-check-size)) / 2));
    margin-inline: 0;
}

.fx-field-inline :is(input[type="checkbox"], input[type="radio"]) {
    margin-block-start: 0;
}

/* â•â• SHAPE IS THE AFFORDANCE. DO NOT "FIX" THESE THREE LINES. â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * This is the ONE place in the design system where the sharp corner direction
 * must NOT be applied literally, and the next person to sweep the file for round
 * corners needs to read this before reaching for the radius scale.
 *
 * A user reads a selection control's BEHAVIOUR off its silhouette, before any
 * label, any grouping and any instruction:
 *     CIRCLE  = pick exactly one of these        â†’ radio
 *     SQUARE  = pick any number of these         â†’ checkbox
 *     PILL    = this is on or off right now      â†’ switch
 * Squaring a radio does not make it look sharper, it makes the control silently
 * LIE about its own behaviour. On a legal form â€” a case type, a court, a consent
 * to disclose privileged material â€” a user who mistakes single choice for multi
 * choice files the wrong record. That is a defect, not a style opinion.
 *
 * The tick box is fx-radius-xs (4px), which is the radius floor of the whole
 * system and the reference's own checkbox corner. The circle and the pill are
 * the two exemptions, and they are permanent. */
:is(.form-check-input, input)[type="checkbox"] { border-radius: var(--fx-radius-xs); }
:is(.form-check-input, input)[type="radio"]    { border-radius: var(--fx-radius-circle); }
/* The switch track restates the pill at higher specificity in section 12.1,
 * because a switch is an <input type="checkbox"> and would otherwise inherit the
 * square corner from the line above. */

@media (any-hover: hover) {
    :is(.form-check-input, input[type="checkbox"], input[type="radio"]):hover:not(:disabled) {
        background-color: var(--fx-color-field-bg-hover);
    }
}

/* Checked is a solid brand fill that RISES out of its well â€” the well inverts to
 * an ambient float, so a ticked box reads as raised and an empty one as sunken
 * even in greyscale. The brand fill here is the sanctioned exception documented
 * at the head of this section. */
.form-check-input:checked,
.form-check-input[type="checkbox"]:indeterminate,
input[type="checkbox"]:checked,
input[type="radio"]:checked {
    background-color: var(--fx-color-primary);
    box-shadow: var(--fx-shadow-float-sm);
    /* THE GUTTER STAYS INVISIBLE WHEN CHECKED, AND SAYING SO OUT LOUD IS A FIX.
     *
     * MEASURED IN THE RUNNING APP, 2026-08-03, every checked selection control
     * on the platform:
     *     border: 4px solid rgb(13, 110, 253)
     * which is Bootstrap's own blue, at full strength, on a green legal
     * platform. A checked tick box, a checked radio and a checked switch all
     * wore it, and so did a DISABLED checked box.
     *
     * THE CAUSE IS A LONGHAND BEATING A SHORTHAND, not a missing token. The
     * base rule of this section buys its 24px SC 2.5.8 hit area with
     * `border: var(fx-check-gutter) solid transparent` and relies on
     * background-clip to keep the fill inside it, so the gutter paints nothing
     * and is not a stroke. Bootstrap then ships
     * `.form-check-input:checked { border-color: var(bs-form-check-checked-border-color) }`
     * at (0,2,0), which recolours ONLY the colour longhand and leaves our width
     * and style untouched. Our base rule matches `.form-check-input` at (0,1,0),
     * so it loses, and the transparent gutter becomes a 4px painted ring around
     * a 16px control: two thirds of what the user sees is Bootstrap blue.
     *
     * Restating the colour here, at (0,2,0) in a later sheet, is what wins.
     * NOT an !important: this out-specifies nothing that is flagged, it simply
     * answers a longhand with a longhand at equal weight and later order.
     *
     * IF THE GUTTER EVER NEEDS TO PAINT, section 14's validation ring below is
     * the sanctioned way to do it. Do not delete this line to get there. */
    border-color: transparent;
}

/* The tick and the dot animate in by growing their own background image rather
 * than by transforming the input, which replaced elements do not honour
 * reliably. BOTH are listed: an earlier pass sized only the checkbox tick and
 * left the radio dot on Bootstrap's `contain`, so the dot rendered noticeably
 * larger than the tick beside it â€” the exact drift fx-check-art exists to stop.
 * The switch is excluded on purpose: its knob must span the full track height,
 * so it keeps `contain` (section 12.1). */
.form-check-input[type="checkbox"]:checked,
.form-check-input[type="radio"]:checked,
input[type="checkbox"]:not(.form-check-input):checked,
input[type="radio"]:not(.form-check-input):checked {
    background-size: var(--fx-check-art) var(--fx-check-art);
    background-position: center;
    background-repeat: no-repeat;
}

/* The switch is a checkbox by type and would be caught by the rule above. */
.form-switch .form-check-input:checked {
    background-size: contain;
}

/* THE SPRING. A separate, locally named keyframe rather than the shared
 * fx-scale-in from 01-base, because the shared entrance also fades from zero
 * opacity and a checkbox that blinks out of existence on every click is a
 * defect, not a flourish. Only the transform is touched here, so the fill and
 * the tick keep their own timing. Attached to :checked only, which means
 * UNCHECKING removes the animation instantly and cannot play it in reverse. */
@media (prefers-reduced-motion: no-preference) {
    :is(.form-check-input, input[type="checkbox"], input[type="radio"]):checked {
        /* No fill mode on purpose. `both` would pin transform: scale(1) for the
         * life of the checked state, and an animation outranks a declaration,
         * so the :active press above would silently stop working. */
        animation: fx-check-spring var(--fx-dur-base) var(--fx-ease-spring);
    }

    /* A switch is not a tick box. Scaling the whole track on check reads as the
     * control jumping; the switch expresses the same event through its knob
     * travel in section 12.1 instead. */
    .form-switch .form-check-input:checked {
        animation: none;
    }
}

@keyframes fx-check-spring {
    from { transform: scale(0.72); }
    to   { transform: scale(1); }
}

/* FOCUS IS THE SHARED OUTLINE, PULLED IN BY THE GUTTER.
 *
 * The element's border box is 24px but its VISIBLE artwork is 16px, four pixels
 * inside it. An outline at the standard +2px offset would therefore sit 6px away
 * from the shape the user can see, which reads as a ring around nothing. So the
 * offset is reduced by exactly the gutter: fx-focus-offset minus fx-check-gutter
 * is -2px, which lands the ring 2px outside the ARTWORK â€” the standard geometry,
 * measured from the thing that is actually painted. The well is untouched, so
 * the control keeps its 3:1 identification while focused. */
.form-check-input:focus-visible,
input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible {
    outline: var(--fx-focus-width) solid var(--fx-color-focus-ring);
    outline-offset: calc(var(--fx-focus-offset) - var(--fx-check-gutter));
}

/* THE ONE PLACE THE GUTTER IS ALLOWED TO PAINT: a failed selection control.
 *
 * A required consent box that has not been ticked has nowhere else to put its
 * error. A text field expresses invalidity as a border colour change (section
 * 14) and a 24px tick box has exactly one border to change, so the transparent
 * hit-area ring becomes the danger ring and the state stays off colour alone
 * because section 14.3's message and glyph sit beside it either way.
 *
 * MEASURED BEFORE THIS RULE EXISTED: `border-color: rgb(220, 53, 69)`, which is
 * Bootstrap's danger red and NOT this platform's. The system's own red is a
 * deeper, less orange tone, and the two side by side in one form is the
 * "from another planet" report at the colour level. Same mechanism as the
 * checked ring above: Bootstrap owns a colour longhand at (0,2,0) and nothing
 * on our side answered it. This rule answers it with the token. */
:is(.form-check-input, input[type="checkbox"], input[type="radio"]):is(.is-invalid, .input-validation-error, [aria-invalid="true"]) {
    border-color: var(--fx-color-danger-fg);
}

.form-check-input:disabled,
input[type="checkbox"]:disabled,
input[type="radio"]:disabled {
    background-color: var(--fx-color-disabled-bg);
    box-shadow: none;
    cursor: not-allowed;
}

.form-check-input:disabled ~ .form-check-label,
.form-check-input:disabled + label {
    color: var(--fx-color-disabled-fg);
    cursor: not-allowed;
}

/* The label is the second half of the hit area: it fills the row height so the
 * whole line is clickable rather than only the 24px box. It is BODY text â€” this
 * is the one label in the form layer that is content rather than chrome, because
 * it is the option itself and not the name of a field. */
.form-check-label,
.form-check > label {
    display: flex;
    /* flex-start, not center, so a label that WRAPS grows downward from a fixed
     * first line instead of sliding its whole block out of line with the box it
     * is supposed to sit beside. The first line is brought to the vertical
     * centre of the row by the padding below rather than by centring the block,
     * which is what keeps a one line and a three line label starting at exactly
     * the same height. */
    align-items: flex-start;
    flex: 1 1 auto;
    /* Matches the row, so the whole strip is clickable and the target tiers with
     * the token rather than with a pointer query written here. */
    min-block-size: var(--fx-control-h-md);
    /* Centres the FIRST LINE in the row: half of whatever the row has spare once
     * one line box is taken out of it. max() clamps it at zero so a future taller
     * leading or a shorter row can never produce a negative pad. */
    padding-block-start: max(0px, calc((var(--fx-control-h-md) - 1em * var(--fx-leading-normal)) / 2));
    min-inline-size: 0;
    line-height: var(--fx-leading-normal);
    color: var(--fx-color-text-muted);
    cursor: pointer;
    user-select: none;
}

/* 12.1 Switch.
 * The knob travel is the second deliberate physical exception: background
 * position accepts no logical keyword, so the two directions are declared
 * separately. Everything else on the switch is direction neutral. The track is
 * a 24px tall element with a 16px visible rail, same technique as above, and the
 * knob therefore stays a 16px round object inside a 24px target row. */
.form-switch {
    align-items: center;
}

/* The track keeps fx-radius-pill. It is one of the two shapes in this file that
 * is DELIBERATELY a pill â€” a switch rail with square corners reads as a broken
 * toggle, not as a sharp one â€” and 00-tokens names it as such.
 * The knob travel is a genuine spring: it overshoots the far end of the rail and
 * settles, which is the whole point of fx-ease-spring existing. */
.form-switch .form-check-input {
    /* Derived, like the tick box, so the coarse tier moves it without a pointer
     * query in this file: the track is the element plus a fixed 20px of travel.
     *     fine    24 + 20 = 44px element, 24px tall  â†’ 36 x 16px visible rail
     *     coarse  28 + 20 = 48px element, 28px tall  â†’ 40 x 20px visible rail
     * Both clear the 24px SC 2.5.8 floor on the short axis, which is the axis
     * that is at risk on a switch. */
    inline-size: calc(var(--fx-check-size) + 1.25rem);
    min-inline-size: calc(var(--fx-check-size) + 1.25rem);
    block-size: var(--fx-check-size);
    border-radius: var(--fx-radius-pill);
    background-color: var(--fx-color-field-bg);
    background-position: 0 center;
    background-size: contain;
    /* The same pair the tick box takes, composed from the same local. This rule
     * is (0,2,0) and would otherwise replace the base list wholesale, which is
     * exactly how an OFF switch would have kept the boundary it just gained and
     * then lost it again on the next edit. */
    box-shadow: var(--fx-check-ring), var(--fx-shadow-well);
    /* fx-dur-base (160ms), NOT fx-dur-slow. 250ms sits inside the 200 to 400ms
     * band that 00-tokens section 7 rules out â€” long enough to wait for, short
     * enough that waiting feels pointless. Nothing in this file goes there. */
    transition:
        background-position var(--fx-dur-base) var(--fx-ease-spring),
        background-color var(--fx-dur-fast) var(--fx-ease-standard),
        box-shadow var(--fx-dur-fast) var(--fx-ease-standard);
}

/* Pressing a switch compresses the TRACK along the inline axis only, so the
 * knob keeps its round shape while the control gives. Direction neutral. */
.form-switch .form-check-input:active:not(:disabled) {
    transform: scaleX(var(--fx-press-scale));
}

.form-switch .form-check-input:checked {
    background-position: 100% center;
    background-color: var(--fx-color-primary);
    /* The track stays recessed when on â€” only its FILL changes â€” so the knob
     * keeps reading as an object sitting inside a groove.
     * NO fx-check-ring HERE, for the same reason a checked tick box drops it:
     * the track is now fx-color-primary, which measures 8.27:1 against the card,
     * so the fill IS the boundary and a neutral hairline drawn over a saturated
     * green would only muddy its edge. */
    box-shadow: var(--fx-shadow-well);
}

/* RTL: the knob must travel toward the inline start, i.e. the physical left. */
[dir="rtl"] .form-switch .form-check-input          { background-position: 100% center; }
[dir="rtl"] .form-switch .form-check-input:checked  { background-position: 0 center; }

/* 12.2 Inline group of checks, e.g. a permission row. */
.form-check-inline {
    display: inline-flex;
    margin-inline-end: var(--fx-space-4);
}

/* 12.3 Card style choice, for exclusive options that deserve description text. */
.fx-check-card {
    display: flex;
    align-items: flex-start;
    gap: var(--fx-space-3);
    /* A choice card is a panel, so it takes the panel radius and the surface
     * padding token rather than a raw space step. */
    padding: var(--fx-surface-pad-sm);
    /* A card at rest on a surface takes the physical EDGE stack, not a float:
     * a float says "detached", which a choice card is not. See 00-tokens 6.
     *
     * LEVEL 2, NOT `fx-color-surface`. CORRECTED 2026-08-03, and it is a zero
     * step rather than a wrong hue. `fx-color-surface` IS `fx-color-level-1` by
     * declaration in both themes, and the app shell now lifts `.lpx-content`
     * into a card whose fill is level-1 â€” so a choice card painted `surface`
     * sits on a plane of exactly its own value, a level step of 0.00, and
     * `fx-shadow-stack` above draws an edge around a panel with no fill
     * difference to enclose. The card read as loose text with a hairline round
     * it. Level 2 is the raised plane and restores the separation the shadow
     * assumes. Same defect and same fix as `.fx-toolbar` in 02-layout and
     * `.frihat-grid.tabulator` in 09-tabulator.
     *
     * THE HOVER AND SELECTED FILLS BELOW ARE UNAFFECTED: both are the tint,
     * which composites over whatever plane it lands on. And a FIELD inside this
     * card is unaffected either way â€” `fx-color-field-bg` is its own token and
     * the well carries its boundary. */
    background-color: var(--fx-color-level-2);
    border: 0;
    border-radius: var(--fx-radius-lg);
    box-shadow: var(--fx-shadow-stack);
    cursor: pointer;
    transition:
        background-color var(--fx-dur-fast) var(--fx-ease-standard),
        box-shadow var(--fx-dur-fast) var(--fx-ease-standard);
}

@media (any-hover: hover) {
    .fx-check-card:hover {
        background-color: var(--fx-color-hover);
    }
}

.fx-check-card:active {
    box-shadow: var(--fx-shadow-press);
}

/* SELECTED is a state of the card, not a focus state, so it is expressed on the
 * element itself and the two can show at the same time without one erasing the
 * other. NEUTRAL: a selected card is a selected row by another name, and the
 * brand moment is already spent on the tick box inside it. */
.fx-check-card:has(:checked) {
    background-color: var(--fx-color-active);
}

/* FOCUS: the standard outline on the container, drawn from the checkbox inside
 * it. The card's own tick box suppresses nothing â€” a click lands on the input,
 * whose ring is the one the user sees; tabbing to the card shows this one. */
.fx-check-card:focus-within {
    outline: var(--fx-focus-width) solid var(--fx-color-focus-ring);
    outline-offset: var(--fx-focus-offset);
}


/* â”€â”€ 13) Floating labels â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * KEPT WORKING, DELIBERATELY QUIET. Linear does not float or overlay labels â€”
 * the platform default is the stacked label of section 5 â€” but the pattern is
 * already in use on the login and tenant-switch pages, so it stays functional
 * and simply stops shouting: the floated label lands on the TERTIARY tier rather
 * than on brand green, which is what it used to do and which 00-tokens 3.9 does
 * not sanction. Do not reach for this on a new form.
 *
 * Bootstrap's floated state uses `transform: scale(.85) translateY(-.5rem)
 * translateX(.15rem)` and an `opacity`, all of which are direction blind: in
 * Arabic the label drifts the wrong way. We drop the inline translate entirely
 * and set a logical transform origin, so the label shrinks toward whichever
 * edge is the inline start. The label is positioned with inset-inline, never
 * with left.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* THE WRAPPER CARRIES A COPY OF THE INLINE GUTTER, and it is the one place in
 * this file a wrapper-level local is read on purpose. The floated LABEL is not
 * a control, so it has no fx-ctl-* of its own and cannot see the ones section 1
 * sets on its SIBLING; without this copy its inline padding had to be written
 * as fx-control-pad-x-sm and would silently stop lining up with the value the
 * moment the field moved to another step. The control below ignores this copy
 * â€” section 1 re-sets the local on the control itself, exactly as the field
 * contract at the head of the file warns. */
.form-floating {
    --fx-ctl-pad-x: var(--fx-control-pad-x-sm);

    position: relative;
}

/* Taller than a plain field by one step: the box has to hold a shrunken label
 * AND a value on separate optical lines, which 40px cannot do without the value
 * touching the label. Set as the LOCAL so the section Z hardening block, which
 * restates min-block-size at a specificity this rule cannot beat, resolves to
 * the same answer instead of having to know this number. */
.form-floating > :is(.form-control, .form-select, textarea, input) {
    --fx-ctl-h: var(--fx-control-h-xl);

    min-block-size: var(--fx-ctl-h);
    padding-block-start: calc(var(--fx-space-4) + var(--fx-space-1));
    padding-block-end: var(--fx-space-1);
}

.form-floating > label {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    z-index: 2;
    max-inline-size: 100%;
    block-size: 100%;
    /* The inline half reads the wrapper's copy of the gutter, so the label's
     * first glyph sits over the value's first glyph at every size step. */
    padding: var(--fx-space-2) var(--fx-ctl-pad-x);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    pointer-events: none;
    font-size: var(--fx-text-sm);
    font-weight: var(--fx-weight-medium);
    letter-spacing: var(--fx-tracking-ui);
    color: var(--fx-color-text-subtle);
    /* The 1px transparent border that used to sit here existed only to match the
     * control's own 1px border so the label's text box lined up with the value.
     * The control has no resting border any more, so keeping it would offset
     * every floating label by exactly one pixel. */
    border: 0;
    transform-origin: 0 0;    /* physical; mirrored for RTL a few rules below */
    /* Token easing at the state-change tier. The label used to settle over
     * fx-dur-base with a decel curve, which read as the label lagging the caret;
     * it now answers at the same speed as the fill under it. */
    transition:
        transform var(--fx-dur-fast) var(--fx-ease-standard),
        color var(--fx-dur-fast) var(--fx-ease-standard);
}

.form-floating > :is(.form-control, .form-select, textarea, input):focus ~ label,
.form-floating > :is(.form-control, .form-select, textarea, input):not(:placeholder-shown) ~ label,
.form-floating > select ~ label,
.form-floating > .form-select ~ label {
    /* Vertical only. No translateX, which is what breaks Bootstrap in RTL. */
    transform: scale(0.82) translateY(calc(var(--fx-space-2) * -1));
    color: var(--fx-color-text-subtle);
    opacity: 1;
}

.form-floating > :is(.form-control, textarea, input):-webkit-autofill ~ label {
    transform: scale(0.82) translateY(calc(var(--fx-space-2) * -1));
}

/* transform-origin takes physical keywords only, so `0 0` above resolves to the
 * physical left. Mirror it for RTL: the shrink must anchor at the right edge. */
[dir="rtl"] .form-floating > label {
    transform-origin: 100% 0;
}


/* â”€â”€ 14) Validation â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * Four vocabularies must look identical:
 *   Bootstrap client side : .is-invalid / .is-valid + .invalid-feedback
 *   jQuery unobtrusive    : .input-validation-error / .field-validation-error
 *   ASP.NET summary       : .validation-summary-errors
 *   Module dialogs        : .frihat-field-error (emitted by the Courts modal)
 *
 * â•â• THE FIELD IS NOT FILLED. THIS IS THE CHANGE THAT MATTERS. â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * The previous pass tinted an invalid control to fx-color-danger-bg and doubled
 * its well. Linear has no red-tinted input background â€” there is no such colour
 * in their system at all, and there is a good reason: a filled field puts a
 * low-contrast wash UNDERNEATH the user's own words, and on this platform those
 * words are privileged legal content. A lawyer typing into a rejected field
 * should not watch their own sentence sink into pink.
 *
 * So an error is exactly two things:
 *   1. A BORDER COLOUR CHANGE â€” a 2px danger stroke, the third and last
 *      sanctioned stroke-return context in this file after prefers-contrast and
 *      forced-colors. It is 2px rather than 1px because fx-border-width drops to
 *      a genuine half pixel at 2dppx, and an error boundary that thins out on a
 *      Retina panel is not a boundary. box-sizing is border-box, so nothing
 *      reflows when it arrives.
 *   2. A 12px MESSAGE BELOW, in fx-color-danger-fg, carrying a mask-drawn
 *      warning glyph. The glyph is not optional: it is what keeps the state off
 *      colour alone for greyscale, low vision and colour blindness.
 * The WELL SURVIVES, so an invalid field is still identifiable as a field.
 * The TEXT COLOUR IS NOT CHANGED, for the reason above.
 *
 * A VALID FIELD GETS NOTHING. No green fill, no green ring. Success is the
 * absence of failure, and the .valid-feedback message is there for the rare form
 * that genuinely needs to confirm something. Painting every accepted field green
 * is what makes a long form look like a traffic light.
 *
 * VALIDATION ARRIVES rather than simply appearing: the control shakes once on
 * the inline axis and the message rises in. Both are inside a
 * prefers-reduced-motion: no-preference block, so a vestibular user gets the
 * identical border, glyph and colour treatment with no movement at all and no
 * information is carried by the motion.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */

/* 14.1 Invalid control. */
:is(.form-control, .form-select, textarea, select, input).is-invalid,
:is(.form-control, .form-select, textarea, select, input).input-validation-error,
:is(.form-control, .form-select, textarea, select, input)[aria-invalid="true"] {
    --fx-ctl-border: var(--fx-border-width-strong) solid var(--fx-color-danger-fg);
    /* THE WELL IS DELIBERATELY NOT RESTATED HERE. It arrives from whatever the
     * control's resting state set fx-ctl-shadow to, which is what keeps an
     * invalid field identifiable AND keeps a disabled or readonly field flat
     * when it also fails validation. Re-asserting fx-shadow-well in this rule
     * would out-specify section 2's disabled rule and light a dead field up. */
    /* THE SHORTHAND IS RE-APPLIED HERE, AND WITHOUT IT THE LOCAL ABOVE IS
     * DECORATION. This is the "a longhand beats a shorthand at higher
     * specificity" trap, and it cost this rule its colour on every field ABP
     * actually renders.
     *
     * MEASURED IN THE RUNNING APP, 2026-08-03:
     *     input.is-invalid                  border 2px rgb(180, 35, 24)   ours
     *     input.form-control.is-invalid     border 2px rgb(220, 53, 69)   BOOTSTRAP
     *     textarea.form-control.is-invalid  border 2px rgb(220, 53, 69)   BOOTSTRAP
     *     select.form-select.is-invalid     border 2px rgb(220, 53, 69)   BOOTSTRAP
     *     input.form-control.input-validation-error   rgb(180, 35, 24)    ours
     * The pattern is exact: the field is wrong precisely when it carries a
     * BOOTSTRAP class, which is every field ABP and jQuery validation emit, and
     * right on the bare elements a hand written test happens to use. That is
     * why this read as correct until it was measured on a real form.
     *
     * WHY. The local set above is fine and resolves to the right value. But the
     * declaration that CONSUMES it, `border: var(fx-ctl-border)`, lives in
     * section 1, whose selector matches `.form-control` at (0,1,0). Bootstrap
     * ships `.form-control.is-invalid { border-color: â€¦ }` at (0,2,0). A colour
     * longhand at (0,2,0) beats a border shorthand at (0,1,0) no matter which
     * file is later, so section 1 painted the WIDTH and Bootstrap painted the
     * COLOUR of the same edge. This rule is already (0,2,0) and later, so simply
     * naming the shorthand here settles it with no flag.
     *
     * IT IS THE COLOUR LONGHAND AND NOT THE `border` SHORTHAND, AND THAT CHOICE
     * IS THE WHOLE CARE OF THIS FIX. A shorthand here would be (0,2,0) against
     * section 16.4's forced-colours restore at (0,1,0) and section 17's printed
     * ruled line at (0,1,0), and it would beat BOTH â€” reintroducing, for every
     * validated field, precisely the two defects block Z.1 was written to record:
     * an invisible rectangle in Windows High Contrast, and a printed case form
     * with no line under the value. Specificity does not care that those tiers
     * are written later in the file. A colour longhand answers Bootstrap's
     * colour longhand exactly and touches nothing else: the WIDTH still arrives
     * from section 1's shorthand reading fx-ctl-border, so the local remains the
     * single source of this border's weight and a consumer retuning it still
     * moves this rule. Measured after the change: 2px in the app, 2px inside
     * lpx-content, ruled line intact in print, ButtonBorder intact in forced
     * colours. */
    border-color: var(--fx-color-danger-fg);
    /* Bootstrap paints its own validation icon into the background. Suppressed:
     * our glyph lives in the message, where it survives forced colours. */
    background-image: none;
}

/* â•â• 14.1a INVALID AND FOCUSED â€” THE TWO SIGNALS ARE SEPARATED BY GEOMETRY,
 *    NEVER BY HUE. RULED 2026-08-03. â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
 *
 * THIS RULE USED TO SAY: "Two different colours at two different radii, 2px
 * apart â€” which is exactly how a user tells where I am from what is wrong."
 * The first half was true and the second half was never measured. It is now,
 * on the Courts create dialog, in both themes:
 *
 *     LIGHT   border rgb(180, 35, 24)  vs  outline rgb(20, 90, 50)   1.258:1
 *     DARK    border rgb(242,119,107)  vs  outline rgb(53,168, 98)   1.101:1
 *
 * Two strokes at 1.1 to 1.26:1 are THE SAME GREY. The dark theme is the worse
 * of the two, and the primary write path of the product â€” every create and every
 * edit dialog â€” was drawing a red ring inside a green one and calling the pair
 * two states. Rendered, it reads as one muddy band about 6px thick. Each half
 * was correct on its own: the tonal red replaced Bootstrap's #dc3545 and the
 * green ring was added where no focus indicator existed. They were simply never
 * rendered together.
 *
 * â•â• WHY LUMINANCE SEPARATION IS NOT AVAILABLE, PROVEN RATHER THAN ASSERTED â•â•
 *
 * The obvious fix is to move one of the two colours until they are 3:1 apart.
 * IT IS ARITHMETICALLY IMPOSSIBLE HERE, and the proof is short enough to write
 * down so nobody spends an afternoon rediscovering it. Take the light theme,
 * where the field sits on white, and let Lr be the danger colour's relative
 * luminance. The focus ring is green-800 at Lg = 0.0768 and cannot move: it is
 * the platform's one focus colour and a ring that changes hue per field state
 * is a worse defect than the one being fixed. Then:
 *     the danger stroke must clear 3:1 against the white behind it  â†’  Lr <= 0.30
 *     the danger stroke must clear 3:1 against the ring             â†’  Lr >= 0.33
 * There is no such number. Any two strokes dark enough to be seen against a
 * light surface are necessarily close to each other. The same holds inverted in
 * dark. So the distinction CANNOT live in colour, and a system that tried would
 * have been relying on hue alone in any case, which SC 1.4.1 forbids and a
 * greyscale check catches immediately.
 *
 * â•â• WHAT IT LIVES IN INSTEAD: WEIGHT, AND A CHANNEL WIDER THAN EITHER STROKE â•
 *
 * Focus keeps the ring, because "where am I" must look identical on every
 * control on the platform and the OUTERMOST ring is where a user looks for it.
 * The invalid state keeps the box. What changes is that the two stop being the
 * same size and stop touching:
 *
 *     BEFORE   2px danger | 2px surface | 2px ring     three equal bands
 *     AFTER    2px danger | 4px surface | 3px ring     a channel, not a stripe
 *
 * MEASURED as a greyscale luminance profile across the edge, one value per
 * pixel column, which is the check that matters because it is the one the
 * colours cannot pass:
 *     LIGHT   7.7 7.7 7.7 | 100 100 100 100 | 11 11      ring, channel, danger
 *     DARK   29.6 x3      |  1.6 x4         | 33.1 x2
 * Both signals independently clear SC 1.4.11 against the channel between them,
 * which is the surface the field sits on and not a third colour anybody has to
 * maintain:
 *     LIGHT   ring 8.27:1 Â· danger 6.57:1      DARK   ring 5.26:1 Â· danger 5.79:1
 * And the two strokes are still 1.26 and 1.10:1 apart, which no longer matters:
 * NOTHING IN THIS DESIGN ASKS A USER TO TELL RED FROM GREEN.
 *
 * â•â• THE TWO DECLARATIONS ARE LOCALS, AND THAT IS THE LOAD-BEARING PART â•â•â•â•â•â•
 *
 * Writing `outline-width` and `outline-offset` here would have been INERT on
 * every page in the app shell. Section Z's focus rule sets both from the tokens
 * at (0,2,1) and sits later in the file, and a media query adds no specificity
 * â€” this is the exact trap Z.1 was written to record, one weight up. Retuning
 * the TOKENS on the element instead means every rule that reads them follows,
 * including section Z, including section 16.3's increased-contrast promotion,
 * without a single selector being escalated. Verified in the running app inside
 * .lpx-content: 3px at 4px offset, both themes.
 *
 * FORCED COLOURS. 01-base repaints the outline with Highlight and section 16.4
 * gives the invalid field ButtonBorder, so the two signals separate by SYSTEM
 * COLOUR there, which the operating system guarantees to be distinguishable.
 * 01-base writes that outline with literals, so the geometry equalises in that
 * mode; it does not need to differ when the colours already do.
 *
 * PREFERS-CONTRAST: MORE. fx-focus-width is already 3px from 00-tokens 11, so
 * the calc below takes the ring to 4px against a 2px danger stroke and the step
 * grows rather than collapsing. Checked, not assumed.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
:is(.form-control, .form-select, textarea, select, input).is-invalid:is(:focus, :focus-visible),
:is(.form-control, .form-select, textarea, select, input).input-validation-error:is(:focus, :focus-visible),
:is(.form-control, .form-select, textarea, select, input)[aria-invalid="true"]:is(:focus, :focus-visible) {
    /* One step heavier than the danger stroke it has to be told apart from.
     * Derived, never a literal, so both halves move with the border scale. */
    --fx-focus-width:  calc(var(--fx-border-width-strong) + var(--fx-border-width));
    /* The channel. Twice the danger stroke, so it can never be misread as part
     * of either edge. */
    --fx-focus-offset: calc(var(--fx-border-width-strong) * 2);
    --fx-ctl-border: var(--fx-border-width-strong) solid var(--fx-color-danger-fg);
    --fx-ctl-bg: var(--fx-color-field-bg-focus);
    /* Re-applied for the same reason as the resting rule above, one weight up,
     * and as the colour longhand for the same reason too. Bootstrap's
     * `.form-control.is-invalid:focus` carries a border-color at (0,3,0), which
     * would beat the (0,2,0) written at rest, so a field that was correct at
     * rest would go Bootstrap red the instant it received focus. The width still
     * comes from the local through section 1. */
    border-color: var(--fx-color-danger-fg);
}

/* The shake. Small â€” 3px each way, well under the 5 flashes / large movement
 * thresholds â€” and it runs exactly once, at fx-dur-base rather than the old
 * fx-dur-slow so it does not sit in the banned 200 to 400ms band. The
 * displacement is expressed with translateX because no logical transform
 * function exists; it is symmetric about zero, so it is direction neutral and
 * needs no RTL mirror. */
@media (prefers-reduced-motion: no-preference) {
    :is(.form-control, .form-select, textarea, select, input):is(.is-invalid, .input-validation-error, [aria-invalid="true"]) {
        animation: fx-field-shake var(--fx-dur-base) var(--fx-ease-standard) 1;
    }
}

@keyframes fx-field-shake {
    0%, 100% { transform: translateX(0); }
    18%      { transform: translateX(-3px); }
    38%      { transform: translateX(3px); }
    58%      { transform: translateX(-2px); }
    78%      { transform: translateX(1px); }
}

/* ══ 14.1b THE DANGER STROKE HAS TO CROSS TO select2's OWN BOX, BECAUSE THE
 *    ELEMENT WE MARK IS NOT THE ELEMENT THE USER SEES. ═══════════════════════
 *
 * Every dialog on this platform makes its dropdowns searchable centrally:
 * `frihat.dialog.open()` calls `frihat.select.enhanceAll(dialogEl)` right after
 * the append. select2 4.1 then clips the native control to one square pixel
 * with `select2-hidden-accessible` and renders its own box as that select's
 * IMMEDIATE NEXT SIBLING — read out of the vendored build rather than assumed:
 * `_placeContainer` is `e.insertAfter(this.$element)`, and the clip is
 * `position:absolute;width:1px;height:1px;clip-path:inset(50%)`, all flagged.
 *
 * `frihat.field.setError` writes `.is-invalid` and `aria-invalid="true"` onto
 * the native select, which after enhancement is the INVISIBLE one. The two
 * halves of an error then behaved differently, and only one half was broken:
 *   · THE MESSAGE ROW WAS ALWAYS FINE, and is deliberately not touched here.
 *     Section 14.4's `.fx-field:has(:is(.is-invalid, …))` matches a clipped
 *     descendant perfectly well — `:has()` tests the tree, not the rendering —
 *     so the sentence and its warning glyph appeared as designed.
 *   · THE FIELD WAS NEVER RED. 14.1 paints `border-color` on the element that
 *     carries the class, and after enhancement that element is one clipped
 *     pixel sitting outside the layout.
 * So a lawyer read "هذا الحقل مطلوب" underneath a control with no mark on it at
 * all, on every enhanced dialog in the product — المواعيد والقضايا والشيكات
 * والمهام والدفعات وغيرها. The defect is fixed in the shared layer and not in
 * the screen that revealed it, per CLAUDE.md 2.7: ONE shared enhancement made
 * every dialog behave this way, so ONE shared rule is what ends it. A page
 * level patch would have fixed one dialog and left the rest, silently, with
 * nothing to grep for.
 *
 * KEYED ON THE LIBRARY'S OWN CLASSES, NEVER ON `fx-select2`. That skin class is
 * handed to select2 as `selectionCssClass` by frihat-select.js, so it exists
 * only where OUR script ran and is absent from every instance ABP, LeptonX or a
 * module initialises directly. That is the precise mistake section 10.1c was
 * rewritten to undo — it is why select2 shipped unthemed on most screens — and
 * repeating it here would ship a danger stroke that appears on some dialogs and
 * not on others, which is worse than none at all. `--single` is dropped for the
 * same reason the focus rule drops it: a multi-select must fail identically.
 *
 * TOKENS, NOT LITERALS. `--fx-color-danger-fg` is the same semantic token 14.1
 * paints a text input with, so an invalid dropdown and an invalid text field
 * are the same red in all SIXTEEN themes (eight families times light and dark).
 * A hex or an `--fx-p-*` primitive would be right in two of them and wrong in
 * fourteen.
 *
 * ── THE WEIGHT, STATED RATHER THAN HOPED FOR ─────────────────────────────────
 * Three rules already name this border, and the tie-break is NOT source order,
 * because one of them lives in a module stylesheet that loads AFTER this
 * bundle:
 *     vendor  `.select2-container--default .select2-selection--single`  (0,2,0)
 *     ours    10.1c's resting box, container class doubled              (0,4,0)
 *     module  `.select2-container.frihat-select2 .select2-selection--single`
 *             in FLP.CaseManagement Pages/Cases/Index.css               (0,3,0)
 * The 10.1c resting box at (0,4,0) is the one that has to be cleared. This
 * selector is
 *     select (0,0,1) + :is(…) (0,1,0) + .select2-container times 3 (0,3,0)
 *     + .select2-selection (0,1,0)   =   (0,5,1)
 * which clears all three WITH NO `!important`. The tripled container class is
 * this file's existing idiom for buying weight without naming a theme (see
 * section 2 and 10.1c). A flag was not merely unnecessary but wrong: a module
 * page is ALLOWED to re-skin this control, and a flag would take that away.
 *
 * LONGHANDS, NOT THE `border` SHORTHAND — the same choice, for the same reason,
 * as 14.1. A shorthand at (0,5,1) would also beat 16.4's forced-colours restore
 * and 17's printed ruled line, both written at (0,1,0), reintroducing exactly
 * the two defects those sections exist to prevent. Specificity does not care
 * that they are written later in the file.
 *
 * NOTHING REFLOWS when the stroke doubles: the vendor ships
 * `box-sizing: border-box` on both `.select2-selection--single` and
 * `.select2-selection--multiple`, measured in the vendored select2.min.css, so
 * the 2px edge is drawn inside the control's own height. It is 2px rather than
 * 1px for 14.1's reason — `--fx-border-width` is a genuine half pixel at 2dppx,
 * and an error boundary that thins out on a Retina panel is not a boundary. */
select:is(.is-invalid, .input-validation-error, [aria-invalid="true"])
    + .select2-container.select2-container.select2-container .select2-selection {
    border-color: var(--fx-color-danger-fg);
    border-width: var(--fx-border-width-strong);
}

/* INVALID AND FOCUSED, ON select2's THREE FOCUS STATES. This rule sets LOCALS
 * ONLY, and that is the load-bearing part — exactly as in 14.1a. The outline is
 * drawn by 10.1c's focus rule, which reads `--fx-focus-width` and
 * `--fx-focus-offset` off this element; retuning the tokens here means that
 * rule follows without a single selector being escalated, and the platform
 * keeps ONE focus rule for this control. Writing `outline-width` here instead
 * would be a second, competing source of the same edge.
 *
 * The geometry is 14.1a's ruling, unchanged: the focus indicator and the danger
 * stroke are separated by WEIGHT AND A CHANNEL, never by hue, because the
 * measured contrast between the two colours is 1.26:1 in light and 1.10:1 in
 * dark — the same grey — and no two strokes dark enough to be seen against a
 * light surface can be 3:1 apart from each other. FOCUS STAYS A SOFT GLOW: this
 * rule introduces no outline of its own, and 10.1c's `outline: … transparent`
 * carrying `--fx-shadow-field-focus` is left exactly as it is.
 *
 * THREE ARMS, because select2 marks focus three different ways and only one of
 * them fires on a keyboard tab. `select2-container--focus` is NOT applied on
 * plain keyboard focus — measured on /Cases, 2026-08-29, and recorded at length
 * in 10.1c — so the selection span's own `:focus` is listed first and is the
 * one that actually fires; the two container states cover the opened and the
 * script-focused cases. Mirroring 10.1c's arms exactly is deliberate: if that
 * rule's hooks are ever corrected, this one must be corrected with it. */
select:is(.is-invalid, .input-validation-error, [aria-invalid="true"])
    + .select2-container.select2-container.select2-container .select2-selection:is(:focus, :focus-visible),
select:is(.is-invalid, .input-validation-error, [aria-invalid="true"])
    + .select2-container.select2-container.select2-container--focus .select2-selection,
select:is(.is-invalid, .input-validation-error, [aria-invalid="true"])
    + .select2-container.select2-container.select2-container--open .select2-selection {
    /* One step heavier than the danger stroke it has to be told apart from.
     * Derived, never a literal, so both halves move with the border scale. */
    --fx-focus-width:  calc(var(--fx-border-width-strong) + var(--fx-border-width));
    /* The channel. Twice the danger stroke, so it can never be misread as part
     * of either edge. */
    --fx-focus-offset: calc(var(--fx-border-width-strong) * 2);
}

/* THE ARRIVAL, so an enhanced select is not the one field on the form that
 * turns red in silence. Same keyframes, same duration and the same single
 * repetition as the text input above, inside the same `prefers-reduced-motion`
 * gate, so a vestibular user gets the identical border, glyph and colour with
 * no movement and no information carried by the motion.
 * The transform is applied to the SELECTION rather than to the container, which
 * is the direct analogue of shaking the `<input>` itself; select2 4.1 attaches
 * its dropdown to `<body>` (AttachBody, noted in 10.1c), so the panel is not a
 * descendant here and this transform cannot become its containing block. */
@media (prefers-reduced-motion: no-preference) {
    select:is(.is-invalid, .input-validation-error, [aria-invalid="true"])
        + .select2-container.select2-container.select2-container .select2-selection {
        animation: fx-field-shake var(--fx-dur-base) var(--fx-ease-standard) 1;
    }
}

/* 14.2 Valid control. DELIBERATELY EMPTY OF FIELD STYLING â€” see the note above.
 * Bootstrap's own green border and embedded tick image are suppressed here and
 * nothing replaces them; the confirmation, where a form needs one, is the
 * .valid-feedback message in 14.3. */
:is(.form-control, .form-select, textarea, select, input).is-valid,
:is(.form-control, .form-select, textarea, select, input).is-valid:is(:focus, :focus-visible) {
    --fx-ctl-border: 0;
    /* NO `border` OR `border-color` RESTATEMENT HERE, AND THAT IS CHECKED RATHER
     * THAN ASSUMED. 14.1 has to answer Bootstrap's colour longhand because an
     * invalid field draws a real 2px edge whose COLOUR Bootstrap recolours. A
     * valid field draws NO edge: the local is zero, so section 1's shorthand
     * resolves to `border: 0` and a Bootstrap green border-color at (0,2,0)
     * lands on a zero-width border and paints nothing. Measured on
     * `.form-control.is-valid` in the running app: 0px, both inside and outside
     * the app shell. Adding a shorthand here to "match 14.1" would out-specify
     * section 16.4 and section 17 for no gain and would blank a valid field in
     * Windows High Contrast and drop its printed ruled line. See Z.1. */
    background-image: none;
}

/* 14.3 Messages. 12px â€” fx-text-xs â€” which is the reference's caption step and
 * the smallest size in this system that is allowed to carry a readable sentence.
 * fx-text-2xs (11px) is contractually micro labels only and must never be used
 * here. */
.invalid-feedback,
.field-validation-error,
.frihat-field-error,
.fx-field-error {
    display: flex;
    align-items: flex-start;
    gap: var(--fx-space-1);
    margin-block-start: var(--fx-space-1);
    font-size: var(--fx-text-xs);
    line-height: var(--fx-leading-normal);
    font-weight: var(--fx-weight-medium);
    letter-spacing: var(--fx-tracking-ui);
    color: var(--fx-color-danger-fg);
}

/* The message RISES IN on the shared entrance from 01-base rather than on a
 * keyframe of its own, so a validation message and a list row arrive with the
 * identical curve and distance. Gated, and 01-base's killswitch drops it
 * outright under reduce. */
@media (prefers-reduced-motion: no-preference) {
    .invalid-feedback,
    .field-validation-error:not(:empty),
    .frihat-field-error,
    .fx-field-error,
    .validation-summary-errors {
        animation: fx-rise-in var(--fx-dur-base) var(--fx-ease-decel) both;
    }
}

.valid-feedback,
.field-validation-valid:not(:empty),
.fx-field-success {
    display: flex;
    align-items: flex-start;
    gap: var(--fx-space-1);
    margin-block-start: var(--fx-space-1);
    font-size: var(--fx-text-xs);
    line-height: var(--fx-leading-normal);
    letter-spacing: var(--fx-tracking-ui);
    color: var(--fx-color-success-fg);
}

/* 14.3a A WARNING IN THE MESSAGE ROW. Some checks inform without refusing, the
 * first being a court case number repeated within one court (Cases dialog,
 * 2026-10-06): the save is allowed, so the sentence must not read as an error.
 * The modifier sits on the SAME row element, so the reserved row, the size and
 * the triangle glyph (currentColor) are shared; only the tone changes, and it is
 * the semantic warning token, correct in all sixteen themes. Two classes, so it
 * outranks the single class danger colour above without !important. The control
 * itself is never marked invalid for a warning. */
.frihat-field-error.fx-field-warning,
.fx-field-error.fx-field-warning {
    color: var(--fx-color-warning-fg);
}

/* The glyph. Mask based, so its colour is a token and the SVG stays neutral. */
.invalid-feedback::before,
.field-validation-error::before,
.frihat-field-error::before,
.fx-field-error::before,
.validation-summary-errors > span::before {
    content: "";
    flex: 0 0 auto;
    inline-size: var(--fx-icon-xs);
    block-size: var(--fx-icon-xs);
    margin-block-start: 0.15em;
    background-color: currentColor;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1.2 15.8 14.8H.2L8 1.2zm-.95 4.3v4.4h1.9V5.5h-1.9zm0 5.6v1.9h1.9v-1.9h-1.9z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1.2 15.8 14.8H.2L8 1.2zm-.95 4.3v4.4h1.9V5.5h-1.9zm0 5.6v1.9h1.9v-1.9h-1.9z'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
}

/* 14.3b AN EMPTY MESSAGE ROW PAINTS NOTHING. Inside .fx-field the reserve rule
 * (14.4) hides an empty row; a dialog that builds its rows outside .fx-field got
 * the glyph alone under every field, a red triangle with no sentence (found
 * 2026-10-07 on the Reception correction and void dialogs). A warning sign that
 * says nothing is wrong on every page, so it is suppressed here, once. */
.invalid-feedback:empty::before,
.field-validation-error:empty::before,
.frihat-field-error:empty::before,
.fx-field-error:empty::before {
    content: none;
}

.valid-feedback::before,
.fx-field-success::before {
    content: "";
    flex: 0 0 auto;
    inline-size: var(--fx-icon-xs);
    block-size: var(--fx-icon-xs);
    margin-block-start: 0.15em;
    background-color: currentColor;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M13.6 4.2 6.3 11.5 2.4 7.6l1.4-1.4 2.5 2.5 5.9-5.9z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M13.6 4.2 6.3 11.5 2.4 7.6l1.4-1.4 2.5 2.5 5.9-5.9z'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
}

/* The unobtrusive placeholder span is empty until validation runs; keep it out
 * of the flow so it does not add a stray gap. */
.field-validation-valid:empty { display: none; }

/* 14.4 Reserved message row.
 * Inside .fx-field the message slot always occupies its line, hidden rather
 * than removed, so the form does not jump when validation fires. Scoped to
 * .fx-field on purpose: vanilla Bootstrap pages keep Bootstrap's own toggling.
 * The reserved height tracks fx-text-xs because that is what 14.3 now sets â€” if
 * the two ever disagree the row reserves the wrong amount and the jump returns.
 *
 * .frihat-field-error is in BOTH lists below, and the REASON CHANGED on
 * 2026-08-03 while the rule stayed exactly as written.
 *
 * WHAT IT USED TO DEFEND AGAINST â€” recorded as superseded rather than deleted,
 * because it explains the shape of the rule. The Courts and Cases dialog scripts
 * created and destroyed the message element at runtime and toggled it with
 * jQuery `show()` / `hide()`, so a field carrying it was the one case on the
 * platform where the message node appeared and disappeared from the DOM under
 * us. Leaving it out of the reserve list, as an earlier pass did, meant the
 * module dialogs kept the layout jump the rest of the platform had been fixed
 * for.
 *
 * WHAT ACTUALLY HAPPENS NOW. All three module dialogs were rewritten and the
 * element is ALWAYS PRESENT IN THE DOM AND IS EMPTIED RATHER THAN HIDDEN. The
 * `setFieldError()` helper in each script writes `textContent` and toggles
 * `.is-invalid` and `aria-invalid` on the control alongside it. So the row is
 * reserved from the moment the dialog opens, the message is set and cleared as
 * TEXT, and the `:not(:empty)` arm in the reveal rule below is what the helper
 * is driving. The rule is being consumed exactly as designed â€” nothing here
 * needs to change, and nothing here should be "simplified" on the assumption
 * that the empty case no longer occurs. It is now the RESTING case.
 *
 * WHICH FIELDS GET A ROW IS A DIALOG DECISION, NOT THIS FILE'S. This rule
 * reserves a line for as long as the element EXISTS, so the scripts choose where
 * to emit one: in the Cases dialog only `required` fields do. That is
 * deliberate and worth stating, because the trade-off is not obvious â€” the form
 * has twenty-two fields, and reserving all twenty-two would add twenty-two
 * permanently blank lines to a dialog that already scrolls. The rule the scripts
 * follow is "the fields that can actually fail are the fields that reserve". A
 * field with no row can still be marked invalid (`.is-invalid` draws the border
 * in 14.1) â€” it simply has nowhere to put a sentence, so it must not be given
 * one. If a non-required field ever gains a validation message, it gains a row
 * at the same time or it reintroduces the jump for that one field. */
.fx-field :is(.invalid-feedback, .valid-feedback, .field-validation-error, .fx-field-error, .frihat-field-error) {
    display: flex;
    visibility: hidden;
    min-block-size: calc(var(--fx-text-xs) * var(--fx-leading-normal));
}

.fx-field:has(:is(.is-invalid, .input-validation-error, [aria-invalid="true"])) :is(.invalid-feedback, .fx-field-error, .frihat-field-error),
.fx-field .field-validation-error:not(:empty),
.fx-field .frihat-field-error:not(:empty),
.fx-field:has(.is-valid) .valid-feedback {
    visibility: visible;
}

/* Explicit escape hatch when a page prefers Bootstrap's collapse behaviour. */
.fx-field.fx-field-no-reserve :is(.invalid-feedback, .valid-feedback, .field-validation-error, .fx-field-error, .frihat-field-error) {
    min-block-size: 0;
}

/* 14.5 Server side summary.
 *
 * The summary is a BLOCK of messages rather than a field, so unlike a control it
 * is allowed the danger tint: nothing of the user's own is written on top of it.
 * The 1px frame and the 4px inline start rule are gone. What replaced the rule is
 * an INSET BAND â€” a box-shadow, so it is fill and depth rather than a stroke â€”
 * offset along the inline axis by fx-summary-bar-x. box-shadow has no logical
 * form, so the sign of that offset is this file's one remaining direction switch
 * and is flipped once, immediately below. */
.validation-summary-errors {
    --fx-summary-bar-x: var(--fx-space-1);

    display: block;
    margin-block-end: var(--fx-space-4);
    padding: var(--fx-surface-pad-sm);
    font-size: var(--fx-text-sm);
    color: var(--fx-color-danger-fg);
    background-color: var(--fx-color-danger-bg);
    border: 0;
    border-radius: var(--fx-radius-md);
    box-shadow:
        inset var(--fx-summary-bar-x) 0 0 var(--fx-color-danger-fg),
        var(--fx-shadow-float-sm);
}

[dir="rtl"] .validation-summary-errors {
    --fx-summary-bar-x: calc(var(--fx-space-1) * -1);
}

.validation-summary-errors ul {
    margin: 0;
    padding-inline-start: var(--fx-space-4);
    list-style: none;
}

.validation-summary-errors li {
    display: flex;
    align-items: flex-start;
    gap: var(--fx-space-1);
    padding-block: var(--fx-space-1);
}

.validation-summary-errors li::before {
    content: "";
    flex: 0 0 auto;
    inline-size: var(--fx-icon-xs);
    block-size: var(--fx-icon-xs);
    margin-block-start: 0.2em;
    background-color: currentColor;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1.2 15.8 14.8H.2L8 1.2zm-.95 4.3v4.4h1.9V5.5h-1.9zm0 5.6v1.9h1.9v-1.9h-1.9z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1.2 15.8 14.8H.2L8 1.2zm-.95 4.3v4.4h1.9V5.5h-1.9zm0 5.6v1.9h1.9v-1.9h-1.9z'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
}

.validation-summary-valid { display: none; }


/* â”€â”€ 15) Professional secret fields â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * Advocates Law 3/1999 art. 28: case and client content is a professional
 * secret. These classes are the PRESENTATION hooks that let a list or detail
 * view show a field as masked with a reveal affordance.
 *
 * WARNING, and it belongs in the code rather than in a document: masking here
 * is visual only. The value is still in the DOM, still in the page source and
 * still in any client side error report. A field that must not reach the
 * browser has to be redacted server side by the AppService. Treat these classes
 * as shoulder surfing protection, never as an access control.
 *
 * THE BEHAVIOUR OF THIS SECTION IS A COMPLIANCE OBLIGATION, NOT STYLING. The
 * 2026-08-02 retune changed COLOURS and TIERS here and nothing else: every
 * masking mechanism â€” text-security, the Gecko overlay fallback, the print
 * mask, the reveal contract â€” is byte-for-byte what it was. Restyle this
 * section freely; never weaken it.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.fx-field-sensitive {
    position: relative;
}

/* An input whose characters are dotted out until the field is revealed. */
/* THE MASKING MECHANISM IS UNCHANGED â€” text-security plus the mono family plus
 * the tracking, byte for byte. The only thing this pass touched in section 15
 * is that the toggle beside it is now floored on both axes; nothing here was
 * routed through a local, because none of it is geometry: the mono family and
 * the 0.14em are properties of a field whose glyphs have been REPLACED BY
 * DISCS, and a consumer must not be able to retune either. Restyle this
 * section freely; never weaken it. */
.fx-field-sensitive :is(input, .form-control),
input.fx-sensitive,
.fx-sensitive-input {
    font-family: var(--fx-font-mono);
    /* POSITIVE tracking, so the Arabic guard in 00-tokens does not apply and
     * none is needed: the glyphs under it have been replaced by discs, so there
     * are no joins to pull apart. */
    letter-spacing: 0.14em;
    -webkit-text-security: disc;   /* Blink and WebKit */
    text-security: disc;
}

.fx-field-sensitive[data-fx-revealed="true"] :is(input, .form-control),
input.fx-sensitive[data-fx-revealed="true"],
.fx-sensitive-input.is-revealed {
    -webkit-text-security: none;
    text-security: none;
    letter-spacing: normal;
    font-family: inherit;
}

/* A read only value in a grid cell or a detail row. Gecko has no text-security,
 * so a static value is masked by overlaying dot glyphs instead. */
.fx-masked-value {
    position: relative;
    display: inline-block;
    min-inline-size: 6ch;
    color: transparent;
    user-select: none;
}

.fx-masked-value::after {
    content: "â€¢â€¢â€¢â€¢â€¢â€¢â€¢â€¢";
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    font-family: var(--fx-font-mono);
    letter-spacing: 0.12em;
    color: var(--fx-color-text-subtle);
    pointer-events: none;
}

.fx-masked-value.is-revealed {
    color: inherit;
    user-select: text;
}

.fx-masked-value.is-revealed::after { content: none; }

/* The reveal affordance. Styling only: the toggle itself must be a real button
 * wired from an external script, never an inline onclick, so a future Content
 * Security Policy is not blocked. */
.fx-reveal-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 32px square fine / 40px coarse, straight off the token tier â€” clears the
     * 24px SC 2.5.8 floor with room to spare and reaches the touch target
     * without a pointer media query in this file. It reads correctly beside 13px
     * labels because the GLYPH inside stays fx-icon-sm; the box around it is
     * what grew. */
    inline-size: var(--fx-control-h-md);
    min-inline-size: var(--fx-control-h-md);
    block-size: var(--fx-control-h-md);
    /* Floored on BOTH axes, unlike .fx-input-action was. block-size alone is a
     * value and not a guarantee: it is beatable by a later rule or by a theme,
     * and this control masks a professional secret, so the affordance that
     * reveals it must not be the one thing on the page a user cannot hit. */
    min-block-size: var(--fx-control-h-md);
    padding: 0;
    color: var(--fx-color-text-subtle);
    background-color: transparent;
    border: 0;
    /* fx-radius-sm, NOT fx-ctl-radius, and deliberately direct. This is an icon
     * BUTTON in the 04-buttons vocabulary that happens to live beside a field;
     * an 8px corner on a 32px square reads as a lozenge, and routing it through
     * the field local would also drag it onto whatever step the field is on. */
    border-radius: var(--fx-radius-sm);
    cursor: pointer;
    transition:
        color var(--fx-dur-fast) var(--fx-ease-standard),
        background-color var(--fx-dur-fast) var(--fx-ease-standard);
}

.fx-reveal-toggle::before {
    content: "";
    inline-size: var(--fx-icon-sm);
    block-size: var(--fx-icon-sm);
    background-color: currentColor;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 3C4.4 3 1.4 5.1 0 8c1.4 2.9 4.4 5 8 5s6.6-2.1 8-5c-1.4-2.9-4.4-5-8-5zm0 8.2A3.2 3.2 0 1 1 8 4.8a3.2 3.2 0 0 1 0 6.4zm0-1.6a1.6 1.6 0 1 0 0-3.2 1.6 1.6 0 0 0 0 3.2z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 3C4.4 3 1.4 5.1 0 8c1.4 2.9 4.4 5 8 5s6.6-2.1 8-5c-1.4-2.9-4.4-5-8-5zm0 8.2A3.2 3.2 0 1 1 8 4.8a3.2 3.2 0 0 1 0 6.4zm0-1.6a1.6 1.6 0 1 0 0-3.2 1.6 1.6 0 0 0 0 3.2z'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
}

/* Promotes a tier, like every other icon affordance in this file. It used to
 * turn brand green, which 00-tokens 3.9 does not sanction. */
@media (any-hover: hover) {
    .fx-reveal-toggle:hover {
        color: var(--fx-color-text);
        background-color: var(--fx-color-hover);
    }
}

.fx-reveal-toggle:focus-visible {
    outline: var(--fx-focus-width) solid var(--fx-color-focus-ring);
    outline-offset: var(--fx-focus-offset);
}

/* A quiet badge marking the field as privileged, shown next to the label. This
 * is a STATUS, so it legitimately carries the warning trio rather than a neutral
 * wash â€” 00-tokens 3.9 site 2 is a filled badge that is genuinely a status, and
 * "this field is a professional secret" is exactly that. */
.fx-sensitive-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--fx-space-1);
    margin-inline-start: var(--fx-space-2);
    padding-inline: var(--fx-space-2);
    padding-block: 0.1em;
    font-size: var(--fx-text-2xs);
    font-weight: var(--fx-weight-semibold);
    color: var(--fx-color-warning-fg);
    /* A tag, so fx-radius-sm â€” the pill it used to be was named, not designed.
     * Fill only; the tint against the label row is the whole boundary. */
    background-color: var(--fx-color-warning-bg);
    border: 0;
    border-radius: var(--fx-radius-sm);
}

.fx-sensitive-badge::before {
    content: "";
    inline-size: var(--fx-icon-xs);
    block-size: var(--fx-icon-xs);
    background-color: currentColor;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a3.5 3.5 0 0 0-3.5 3.5V6H4a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V7a1 1 0 0 0-1-1h-.5V4.5A3.5 3.5 0 0 0 8 1zm0 1.6c1 0 1.9.9 1.9 1.9V6H6.1V4.5c0-1 .9-1.9 1.9-1.9z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a3.5 3.5 0 0 0-3.5 3.5V6H4a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V7a1 1 0 0 0-1-1h-.5V4.5A3.5 3.5 0 0 0 8 1zm0 1.6c1 0 1.9.9 1.9 1.9V6H6.1V4.5c0-1 .9-1.9 1.9-1.9z'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
}


/* â”€â”€ 16) Motion and contrast preferences â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * 16.1 COARSE POINTER â€” DELIBERATELY EMPTY, AND IT MUST STAY THAT WAY.
 *
 * This section used to hold a @media (pointer: coarse) block that re-sized every
 * control in the file. It is gone, because 00-tokens.css ALREADY tiers the whole
 * control ladder on that same query â€” 24/28/32/40/44 becomes 28/32/40/44/48, and
 * the icon and horizontal padding scales move with it. A second coarse block
 * here did not reinforce the tier, it FOUGHT it: it pinned controls to literal
 * rem values that no longer tracked the tokens, and it duplicated the ladder in
 * a second place, which is exactly how the two drift apart.
 *
 * Every size in this file is now DERIVED from a control token, so touch sizing
 * is a property of the token layer and this file states it once, in the
 * component, rather than twice. The results on a coarse pointer, all reached
 * without a query here:
 *     text control      44px   (fx-control-h-lg tier)
 *     small control     40px   (fx-control-h-md tier)
 *     large control     48px   (fx-control-h-xl tier)
 *     checkbox / radio  28px element, 20px artwork
 *     switch            48 x 28px element
 *     check row + label 40px
 *     range thumb       28px
 *     reveal toggle     40px
 *     file trigger      44px
 *     popup item        44px   (fx-menu-item-h tier)
 * WRITE NO COARSE TARGET OVERRIDE HERE. If a TARGET is too small on touch, the
 * fix is the token tier or the derivation, never a second media query â€” every
 * height above arrives through fx-control-h-*, which 00-tokens already steps.
 *
 * THE ONE COARSE QUERY THIS FILE DOES WRITE IS SECTION 1d, AND IT IS NOT A
 * TARGET. It is a 16px floor on fx-ctl-font-size, which exists because iOS
 * Safari zooms the viewport on a field under that size â€” a browser behaviour,
 * not a comfort dimension. The escape hatch this paragraph offers does not reach
 * it: 00-tokens' coarse tier restates the control heights, the paddings, the row
 * heights, the menu and nav heights and the icon sizes, and deliberately no
 * fx-text-* token, so there is no tier to move and no derivation to read. Read
 * 1d before adding a second one; a coarse override for anything that CAN be
 * derived is still wrong.
 *
 * 16.2 Reduced motion. Every entrance, spring, shake and popup transition
 * declared in this file is removed â€” not shortened. A zero duration animation
 * still paints its fill-mode start frame for a tick, which reads as a flash. The
 * STATE is untouched: the same fill, the same depth, the same border, the same
 * outline, arriving instantly. Note that the focus INDICATOR is now an outline â€”
 * a plain declaration, never a keyframe â€” so it cannot be delayed by, damped by,
 * or lost to this branch at all, which is one of the reasons the bloom went. */
@media (prefers-reduced-motion: reduce) {
    .form-control,
    .form-select,
    textarea,
    select,
    input,
    .fx-select-trigger,
    .fx-select-chevron,
    .fx-select-popup,
    .fx-select-item,
    .form-check-input,
    .form-switch .form-check-input,
    .form-floating > label,
    .fx-file-drop,
    .fx-check-card,
    .fx-reveal-toggle,
    .fx-input-action,
    .input-group,
    .invalid-feedback,
    .field-validation-error,
    .frihat-field-error,
    .fx-field-error,
    .validation-summary-errors {
        transition-duration: var(--fx-dur-instant);
        animation: none;
    }

    /* THE RANGE THUMB WAS THE LAST ENTRY IN THE LIST ABOVE AND HAD TO COME OUT.
     * CORRECTED 2026-08-03, alongside the picker rules below and for the same
     * reason. A selector list is invalid IN ITS ENTIRETY if it contains a
     * pseudo-element the engine does not recognise, so `::-webkit-slider-thumb`
     * sitting at the end of a twenty-selector list put the WHOLE damping rule at
     * the mercy of whether Gecko happens to alias that name â€” and the failure
     * mode if it does not is that every entrance, shake and popup transition in
     * this file runs at full length for exactly the users who asked for none.
     * The tier must not depend on a vendor-alias question nobody re-checks. Split
     * out, it cannot: Gecko drops two small rules and keeps the tier. */
    input[type="range"]::-webkit-slider-thumb {
        transition-duration: var(--fx-dur-instant);
        animation: none;
    }

    /* The press compression and the chevron rotation are movement too. The
     * chevron still ROTATES â€” the rotation carries the open state â€” it simply
     * arrives instantly through the damped duration above. */
    :is(.form-check-input, input[type="checkbox"], input[type="radio"]):active,
    .form-switch .form-check-input:active {
        transform: none;
    }

    input[type="range"]:active::-webkit-slider-thumb {
        transform: none;
    }

    input[type="range"]:active::-moz-range-thumb {
        transform: none;
    }

    /* THE PICKER AFFORDANCE (10.2b), IN ITS OWN RULES AND NOT IN THE LIST ABOVE.
     * A selector list is invalid in its entirety if it contains a pseudo-element
     * the engine does not know, so one `::-webkit-calendar-picker-indicator`
     * added to the damping list at the top of this block would delete the WHOLE
     * reduced-motion tier for every Firefox user â€” every entrance, every shake
     * and every popup transition in this file would run at full length for the
     * one group of users who asked for none of it. That is the general trap
     * section Z.1 names: a rule that reaches across an accessibility tier does
     * not fail visibly, it fails exactly where the tier was needed. Separate
     * rules cost four lines and cannot do it. */
    input[type="date"]::-webkit-calendar-picker-indicator {
        transition-duration: var(--fx-dur-instant);
    }

    input[type="time"]::-webkit-calendar-picker-indicator {
        transition-duration: var(--fx-dur-instant);
    }

    input[type="datetime-local"]::-webkit-calendar-picker-indicator {
        transition-duration: var(--fx-dur-instant);
    }

    input[type="month"]::-webkit-calendar-picker-indicator {
        transition-duration: var(--fx-dur-instant);
    }

    input[type="week"]::-webkit-calendar-picker-indicator {
        transition-duration: var(--fx-dur-instant);
    }
}

/* 16.3 Increased contrast.
 *
 * THIS IS ONE OF THE THREE PLACES A RESTING STROKE COMES BACK, and it is
 * deliberate. A user who has asked the operating system for more contrast has
 * told us that fill difference plus depth is not enough for them, so every
 * unstroked control regains a full strength 2px outline drawn INSIDE its own
 * box â€” outline with a negative offset, so nothing reflows and no corner has to
 * be restated. 00-tokens also collapses the dimmed text tiers onto primary under
 * this query, so the help rule below is belt and braces.
 *
 * â•â• THE PLACEHOLDER IS NO LONGER IN THAT LIST, AND ITS REMOVAL IS THE FIX â•â•â•
 *
 * This block used to add `::placeholder` to the group that paints
 * fx-color-text, described as belt and braces alongside the token collapse. It
 * was not belt and braces â€” it sat later in the file than section 3's rule and
 * therefore WON â€” and both it and the collapse were wrong for the same reason.
 * A placeholder painted in body ink is indistinguishable from a value the user
 * typed, so under this query an empty field on a case form looked filled.
 * MEASURED: identical ink, 1.00:1, for a hint and a value.
 *
 * The correct behaviour is a PROMOTION, not a collapse, and it belongs at the
 * token layer where every consumer inherits it: 00-tokens 2.2.2 adds
 * fx-color-text-placeholder and 00-tokens 11 promotes it one rung, tertiary to
 * secondary, instead of onto body ink. Section 1 routes fx-ctl-placeholder
 * through it. This block therefore has nothing left to say about the FORM grade
 * and says nothing.
 *
 * IT STILL HAS SOMETHING TO SAY ABOUT THE SEARCH GRADE. Section 3 puts a search
 * or command hint on the quaternary tier, deliberately below AA, which is right
 * at rest and wrong for a user who has asked the operating system for more
 * contrast. That grade is promoted onto the placeholder token below, so it rises
 * to the same rung as a form hint. Both are hints; neither becomes a value. */
@media (prefers-contrast: more) {
    .form-control,
    .form-select,
    textarea,
    select,
    input:not([type]),
    input[type="text"],
    input[type="email"],
    input[type="password"],
    input[type="number"],
    input[type="tel"],
    input[type="url"],
    input[type="search"],
    input[type="date"],
    input[type="time"],
    input[type="datetime-local"],
    input[type="file"],
    .fx-select-trigger,
    .fx-select-popup,
    .input-group,
    .fx-check-card,
    .fx-file-drop {
        outline: var(--fx-border-width-strong) solid var(--fx-color-text);
        outline-offset: calc(var(--fx-border-width-strong) * -1);
    }

    .form-check-input,
    input[type="checkbox"],
    input[type="radio"] {
        box-shadow: inset 0 0 0 var(--fx-border-width-strong) var(--fx-color-text);
    }

    /* The focus indicator must still beat the resting outline it now sits on, so
     * it is both thicker and pushed outside the box. fx-focus-width is already
     * promoted to 3px by 00-tokens under this query. */
    :is(.form-control, .form-select, textarea, select, input):is(:focus, :focus-visible),
    .fx-select-trigger:focus-visible,
    .input-group:focus-within {
        outline-width: var(--fx-focus-width);
        outline-color: var(--fx-color-focus-ring);
        outline-offset: var(--fx-focus-offset);
    }

    .form-text,
    .fx-help,
    .fx-field-hint,
    .fx-select-chevron {
        color: var(--fx-color-text);
    }

    /* THE SEARCH AND COMMAND HINT, PROMOTED ONTO THE PLACEHOLDER TIER.
     *
     * Written as `:is()` at (0,1,1) for exactly the reason section 3 spells out
     * over its own copy of this selector: a plain comma list would leave
     * `.fx-search-input` at (0,1,0), which loses to section 1's `input[type=â€¦]`
     * arms, and a command box built on a type="text" input would silently keep
     * the sub-AA grade in the one mode where it is least defensible. Matching
     * section 3's weight and sitting later in the file is what settles it. */
    :is(input[type="search"], .fx-search-input, .fx-command-input) {
        --fx-ctl-placeholder: var(--fx-color-text-placeholder);
    }

    /* THE BUTTON MEMBER OF AN INPUT GROUP REGAINS ITS SEAM. Section 11.1 makes a
     * neutral button transparent so the group's well can run unbroken beneath
     * it, which is correct when a fill difference and a well are doing the work â€”
     * and a user who has asked for more contrast has told us they are not. The
     * seam comes back as a real stroke on the edge the button shares with the
     * field. `border-inline-start` needs no RTL mirror: the button follows the
     * control in source order in every group this file has, so the shared edge is
     * its inline start in both directions. */
    .input-group > .btn {
        border-inline-start: var(--fx-border-width-strong) solid var(--fx-color-text);
    }

    /* Its own rule, for the reason spelled out in the reduced-motion block: a
     * webkit pseudo-element in the grouped list above would invalidate the whole
     * increased-contrast tier in Gecko. The glyph is painted THROUGH the mask by
     * background-color, so the tier has to raise `color`, not a text colour. */
    input[type="date"]::-webkit-calendar-picker-indicator {
        color: var(--fx-color-text);
    }

    input[type="time"]::-webkit-calendar-picker-indicator {
        color: var(--fx-color-text);
    }

    input[type="datetime-local"]::-webkit-calendar-picker-indicator {
        color: var(--fx-color-text);
    }

    input[type="month"]::-webkit-calendar-picker-indicator {
        color: var(--fx-color-text);
    }

    input[type="week"]::-webkit-calendar-picker-indicator {
        color: var(--fx-color-text);
    }
}

/* 16.4 Forced colours (Windows High Contrast).
 *
 * THE SECOND PLACE A STROKE COMES BACK, and the most important one. In forced
 * colours mode the user agent throws every author colour away and drops
 * box-shadow entirely â€” which means the fill difference AND the well disappear
 * at once, and an unstroked control would become an invisible rectangle. Borders
 * and outlines are the only things that survive, so they are what the whole
 * component identification falls back to here. System colour keywords are used
 * rather than tokens, because tokens are ignored.
 *
 * Note that focus needs no rescue any more: it is an outline in the base model,
 * and 01-base already repaints it with Highlight under this query. The rule
 * below survives only for the two containers whose focus is expressed with
 * :focus-within rather than :focus-visible. */
@media (forced-colors: active) {
    .form-control,
    .form-select,
    textarea,
    select,
    input,
    .fx-select-trigger,
    .fx-select-popup,
    .input-group,
    .fx-check-card,
    .fx-file-drop {
        border: var(--fx-border-width) solid ButtonBorder;
    }

    .fx-file-drop {
        border-style: dashed;
    }

    .fx-select-item.is-active,
    .fx-select-item[aria-selected="true"],
    .fx-select-item:focus {
        background-color: Highlight;
        color: HighlightText;
        forced-color-adjust: none;
    }

    .input-group:focus-within,
    .fx-check-card:focus-within,
    .fx-file-drop:focus-within {
        outline: var(--fx-focus-width) solid Highlight;
        outline-offset: var(--fx-focus-offset);
    }

    /* â•â• THE FOCUSED FIELD GETS ITS RING BACK HERE â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
     *
     * Since 2026-08-29 a focused field is marked by fx-shadow-field-focus, a
     * box-shadow â€” and forced-colours mode DROPS EVERY box-shadow in the
     * document. Section 2's rule keeps the outline declared at full width and
     * offset in `transparent` precisely so this block has geometry to colour in;
     * without these four lines a focused field in high contrast would have no
     * indicator at all, which is the one place the old detached ring was doing
     * work the glow cannot.
     *
     * Highlight, not ButtonBorder: the resting border above is already
     * ButtonBorder, and a focus ring the same colour as the resting stroke is
     * not a focus ring. */
    :is(.form-control, .form-select, textarea, select, input):focus-visible {
        outline: var(--fx-focus-width) solid Highlight;
        outline-offset: var(--fx-focus-offset);
    }

    :is(.form-control, .form-select, textarea, select, input):is(.is-invalid, .input-validation-error, [aria-invalid="true"]) {
        border: var(--fx-border-width-strong) solid ButtonBorder;
    }

    .form-check-input:checked,
    input[type="checkbox"]:checked,
    input[type="radio"]:checked {
        background-color: Highlight;
        border-color: ButtonBorder;
    }

    /* THE BUTTON MEMBER, WHICH SECTION 11.1 MADE TRANSPARENT. In forced colours
     * the group's fill and its well are both discarded by the user agent, so a
     * transparent member with no stroke is an invisible target sitting inside a
     * field â€” the user cannot see that a reveal toggle exists at all. The shared
     * edge is redrawn for the same reason the containers above regain a border,
     * and `ButtonFace` gives the target a body the user agent will actually
     * paint rather than leaving it as a hole in the control. */
    .input-group > .btn {
        border-inline-start: var(--fx-border-width) solid ButtonBorder;
        background-color: ButtonFace;
        color: ButtonText;
    }

    /* â•â• THE PICKER AFFORDANCE â€” THE ONE RULE IN 10.2b THAT MUST NOT BE SKIPPED
     *
     * Section 10.2b paints the calendar glyph as `background-color` shown through
     * a MASK, and forced colours forces `background-color` to a system colour of
     * the user agent's choosing â€” which for a non-widget box is the CANVAS. The
     * glyph would be painted in the page colour, on the page colour: the only
     * pointer route to the date picker would silently vanish in Windows High
     * Contrast, on a control whose segment order the user already cannot change.
     *
     * `forced-color-adjust: none` opts this one element back out, and it is safe
     * BECAUSE the values below are system keywords rather than author colours â€”
     * so the glyph still tracks whichever high contrast theme the user chose,
     * instead of freezing our palette into a mode built to replace it. Same
     * bargain, and the same justification, as the `.fx-select-item` rule above.
     *
     * Separate rules per type, as everywhere else in this file, so a Gecko engine
     * that knows none of these pseudo-elements drops four small rules and keeps
     * the entire forced-colours tier above them. */
    input[type="date"]::-webkit-calendar-picker-indicator {
        color: ButtonText;
        background-color: ButtonText;
        forced-color-adjust: none;
    }

    input[type="time"]::-webkit-calendar-picker-indicator {
        color: ButtonText;
        background-color: ButtonText;
        forced-color-adjust: none;
    }

    input[type="datetime-local"]::-webkit-calendar-picker-indicator {
        color: ButtonText;
        background-color: ButtonText;
        forced-color-adjust: none;
    }

    input[type="month"]::-webkit-calendar-picker-indicator {
        color: ButtonText;
        background-color: ButtonText;
        forced-color-adjust: none;
    }

    input[type="week"]::-webkit-calendar-picker-indicator {
        color: ButtonText;
        background-color: ButtonText;
        forced-color-adjust: none;
    }
}


/* â”€â”€ 17) Print â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * A printed case form is a document, not a screenshot of an application. Boxes
 * become underlined values, chrome disappears, and errors stay visible because
 * a printed form with a rejected field must still say which field failed.
 *
 * THE THIRD AND LAST PLACE A STROKE COMES BACK. Fills and shadows do not print:
 * most printers and most print settings drop background graphics entirely, so a
 * filled well would come out as an empty patch of paper with no indication that
 * a field was ever there. A printed form therefore reverts to the oldest
 * convention there is â€” a value sitting on a ruled line.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
@media print {
    .form-control,
    .form-select,
    textarea,
    select,
    .fx-select-trigger,
    input:not([type]),
    input[type="text"],
    input[type="email"],
    input[type="password"],
    input[type="number"],
    input[type="tel"],
    input[type="url"],
    input[type="search"],
    input[type="date"],
    input[type="time"],
    input[type="datetime-local"] {
        /* THE WHOLE PRINT RESET IS EXPRESSED AS LOCALS, and that is what makes
         * it survive a consumer. Written as literals â€” which is what these six
         * lines were â€” the reset is (0,1,1) and loses to any layer that states
         * its own geometry more specifically, so a grid field or a themed field
         * printed as a filled box on paper while a form field printed as a
         * ruled line. Set as locals it reaches every control that reads them,
         * at whatever specificity that control's own rules were written at.
         * The ruled line itself stays a real declaration, because there is no
         * resting border in this system for a local to carry. */
        --fx-ctl-h: 0;
        --fx-ctl-pad-x: 0;
        --fx-ctl-pad-y: 0;
        --fx-ctl-radius: 0;
        --fx-ctl-bg: transparent;
        /* currentColor, not `inherit`. They resolve identically here because
         * `color: inherit` is stated below, and currentColor cannot be a
         * CSS-wide keyword arriving through a var() substitution. */
        --fx-ctl-fg: currentColor;
        --fx-ctl-border: 0;
        --fx-ctl-shadow: none;

        min-block-size: var(--fx-ctl-h);
        padding-inline: var(--fx-ctl-pad-x);
        padding-block: var(--fx-ctl-pad-y);
        background-color: var(--fx-ctl-bg);
        border: var(--fx-ctl-border);
        border-block-end: var(--fx-border-width) solid currentColor;
        border-radius: var(--fx-ctl-radius);
        box-shadow: var(--fx-ctl-shadow);
        color: inherit;
        appearance: none;
    }

    /* A popup is transient chrome and has no meaning on paper. */
    .fx-select-popup,
    .fx-select-chevron {
        display: none;
    }

    /* THE HOVER ENTRY IS AS LOAD BEARING AS THE FOCUS ONE, AND FOR THE IDENTICAL
       REASON. A media query adds no specificity, so a bare `.input-group` at
       (0,1,0) is beaten by BOTH state rules in section 11: `:focus-within` and
       â€” since 11.0a â€” `:hover`, each at (0,2,0). Print emulation does not clear
       the pointer, so a group under the cursor when the sheet is generated would
       keep fx-color-field-bg-hover and print a grey slab where the paper wants a
       value on a ruled line. The focus entry has always been here; the hover
       twin is added with the rule that made it necessary, rather than left for
       the drift section Z.1 describes. */
    .input-group,
    .input-group:hover,
    .input-group:focus-within {
        --fx-ctl-bg: transparent;
        --fx-ctl-shadow: none;

        overflow: visible;
    }

    .input-group-text,
    .fx-input-addon {
        background-color: transparent;
        border: 0;
        padding-inline: 0;
    }

    .fx-check-card,
    .fx-file-drop,
    .validation-summary-errors {
        background-color: transparent;
        box-shadow: none;
        border: var(--fx-border-width) solid currentColor;
    }

    .form-label,
    .fx-label,
    .fx-field-label {
        color: inherit;
        font-weight: var(--fx-weight-semibold);
    }

    .form-text,
    .fx-help,
    .fx-field-hint,
    .fx-input-action,
    .fx-reveal-toggle,
    /* ABP's stock reveal toggle, which section 11.1 claims. It is the same
     * control as `.fx-reveal-toggle` beside it and belongs off the page for the
     * same reason: a printed case form is a document, and an affordance that
     * unmasks a password on screen is not part of the record. Named rather than
     * hiding `.input-group > .btn` wholesale, because a group whose trailing
     * member is a real submit action should still show what the form does. */
    .password-visibility-button,
    input[type="file"]::file-selector-button {
        display: none;
    }

    /* The picker affordance, in its own rules â€” a webkit pseudo-element added to
     * the list above would invalidate it in Gecko and take the whole chrome
     * suppression down with it. Chrome on paper is noise; the VALUE prints, and
     * section 17's ruled line is what carries the field. */
    input[type="date"]::-webkit-calendar-picker-indicator {
        display: none;
    }

    input[type="time"]::-webkit-calendar-picker-indicator {
        display: none;
    }

    input[type="datetime-local"]::-webkit-calendar-picker-indicator {
        display: none;
    }

    input[type="month"]::-webkit-calendar-picker-indicator {
        display: none;
    }

    input[type="week"]::-webkit-calendar-picker-indicator {
        display: none;
    }

    .fx-form-grid {
        gap: var(--fx-space-2);
    }

    /* A masked professional secret must stay masked on paper. */
    .fx-masked-value {
        color: transparent;
    }

    /* A printed form with a rejected field must still say which field failed, so
     * every error vocabulary is forced back into view â€” including the reserved
     * rows that section 14.4 hides with visibility. The invalid field keeps a
     * heavier rule under it, because colour is the first thing a monochrome
     * printer discards. */
    :is(.form-control, .form-select, textarea, select, input):is(.is-invalid, .input-validation-error, [aria-invalid="true"]) {
        border-block-end-width: var(--fx-border-width-strong);
    }

    .invalid-feedback,
    .field-validation-error,
    .frihat-field-error,
    .fx-field-error,
    .validation-summary-errors {
        visibility: visible;
        color: inherit;
        background-color: transparent;
        border-color: currentColor;
    }
}


/* â”€â”€ Z) Field hardening â€” winning against the LeptonX content scope â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * THE DEFECT THIS FIXES
 *   Client, from a running build: "text fields and select boxes fields not ok,
 *   not following Linear." The well treatment above is correct and complete, but
 *   it is declared on a bare class list at specificity 0,1,0. LeptonXLite scopes
 *   its own form styling inside the content region â€” `.lpx-content .form-control`
 *   and friends at 0,2,0 â€” which beats us on every page rendered in the app
 *   shell, which is every page. The fields therefore kept the theme's bordered
 *   Bootstrap look while the design system silently lost.
 *
 * WHY IT IS RESTATED RATHER THAN OUT-SPECIFIED AT THE TOP
 *   Raising the base rule to 0,2,0 would force every future component that wants
 *   to restyle a field to escalate too, and specificity wars are how a design
 *   system rots. Instead the base rule stays cheap and overridable, and this one
 *   block re-asserts only the properties LeptonX actually contests, scoped to the
 *   one ancestor that causes the problem. Delete this section the day the theme
 *   stops scoping form controls.
 *
 * PROPERTIES RESTATED, AND WHY EACH ONE
 *   background / box-shadow / border â€” the well itself, which is what makes the
 *   control identifiable at all now that no resting stroke is drawn. Losing
 *   these is not cosmetic: the 3:1 identification cue for SC 1.4.11 lives in
 *   fx-shadow-well. Height, padding and radius follow so a contested field
 *   cannot end up half migrated at 32px with 8px corners.
 *
 *   The border is restated through the LOCAL, `var(--fx-ctl-border)`, not as a
 *   literal `border: 0`. That is the load-bearing detail of this block: a flat
 *   zero here would out-specify section 14 and silently delete the validation
 *   border from every field inside the app shell, which is every field on the
 *   platform. Reading the local means this block re-asserts "whatever the
 *   control's own state decided" rather than "nothing".
 *
 * WHAT WAS REMOVED FROM THIS BLOCK
 *   `outline-color: transparent` on focus. Under the old bloom model that line
 *   suppressed a competing UA outline while a box-shadow drew the indicator.
 *   Under the outline model it DELETES THE FOCUS INDICATOR outright, on every
 *   field on every page in the shell. It is the single worst line the retune
 *   could have left behind and it is gone.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */

.lpx-content .form-control,
.lpx-content .form-select,
.lpx-content textarea,
.lpx-content select,
.lpx-content input:not([type]),
.lpx-content input[type="text"],
.lpx-content input[type="email"],
.lpx-content input[type="password"],
.lpx-content input[type="number"],
.lpx-content input[type="tel"],
.lpx-content input[type="url"],
.lpx-content input[type="search"],
.lpx-content input[type="date"],
.lpx-content input[type="time"],
.lpx-content input[type="datetime-local"],
.lpx-content input[type="month"],
.lpx-content input[type="week"] {
    min-block-size: var(--fx-ctl-h);
    padding-block: var(--fx-ctl-pad-y);
    padding-inline: var(--fx-ctl-pad-x);
    /* THE TYPE PAIR JOINS THE LIST. LeptonX sets its own font-size and
     * line-height on a contested field, and until fx-ctl-font-size existed
     * there was nothing for this block to re-assert them WITH â€” so it did not
     * try, and a field inside the app shell kept the theme's type while taking
     * our height, padding and well. That is a field half migrated, which is a
     * more confusing result than one that lost outright. */
    font-size: var(--fx-ctl-font-size);
    line-height: var(--fx-ctl-leading);
    background-color: var(--fx-ctl-bg);
    background-clip: padding-box;
    background-image: none;
    color: var(--fx-ctl-fg);
    caret-color: var(--fx-ctl-caret);
    border: var(--fx-ctl-border);
    border-radius: var(--fx-ctl-radius);
    box-shadow: var(--fx-ctl-shadow);
}

/* The placeholder tier, re-asserted for the same reason and in the same shape:
 * one rule reading one local, so the form and search grades stay a property of
 * the control rather than of the scope it happens to be rendered in. */
.lpx-content :is(.form-control, textarea, select, input)::placeholder {
    color: var(--fx-ctl-placeholder);
}

/* TWO HEIGHTS THIS BLOCK WOULD OTHERWISE STEAL.
 *
 * The rule above restates min-block-size, and it has to â€” LeptonX sets its own
 * height on a contested field. But it is (0,2,0) and it therefore also beats two
 * legitimate taller cases declared earlier in this file:
 *   Â· a TEXTAREA, whose two-row minimum lives at (0,1,1) in section 8, would
 *     collapse to a single 40px line;
 *   Â· a FLOATING-LABEL field, which needs the extra step at (0,2,0) in section
 *     13 to hold a shrunken label and a value on separate optical lines, would
 *     drop back to 40px and the value would touch the label.
 * Both are restated here at a specificity that wins, immediately after the rule
 * that caused the problem, so the two can never be read apart. */
.lpx-content textarea,
.lpx-content textarea.form-control {
    /* Both halves now arrive from the locals section 8 set, so this block
       re-asserts the SHAPE without knowing the numbers. Section 8 owns the
       two-row floor and the prose leading; this rule only wins the fight. */
    min-block-size: calc(var(--fx-ctl-h) * 2);
    line-height: var(--fx-ctl-leading);
}

.lpx-content .form-floating > :is(.form-control, .form-select, textarea, select, input) {
    min-block-size: var(--fx-ctl-h);
    padding-block-start: calc(var(--fx-space-4) + var(--fx-space-1));
    padding-block-end: var(--fx-space-1);
}

/* THE SIZE LADDER, RE-ASSERTED OVER THIS BLOCK.
 *
 * The steps in section 1b work by redeclaring the fx-ctl-* LOCALS, and the
 * hardening rule above reads those same locals, so in principle a field on any
 * step already survives it. In principle. The failure mode is that anything
 * which ever restates a LITERAL height at 0,2,0 â€” this block, LeptonX, a future
 * vendored sheet â€” silently outranks a 0,1,0 step that only moved a variable,
 * and the field snaps back to the 40px default. That is what happened to the
 * DataTables search box.
 *
 * ONE RULE FOR THE WHOLE LADDER, where there used to be one per variant. With
 * fx-ctl-font-size in the contract there is nothing left for a per-step rule to
 * say: every step is a block of local redeclarations, so re-asserting the
 * properties a geometry regression travels through is identical work for xs,
 * sm, md and lg. The two rules this replaces named fx-text-sm and fx-text-lg as
 * literals, which is the whole defect in miniature â€” the step and the hardening
 * block each held their own copy of the type size, and only source order kept
 * the two agreeing.
 *
 * It carries the ladder at the SAME 0,2,0 the hardening block uses, placed
 * after it, so source order settles the tie in the step's favour.
 *
 * THE WELL IS NOT RESTATED, DELIBERATELY. fx-ctl-shadow is untouched by every
 * step, so `box-shadow: var(fx-ctl-shadow)` from the block above still resolves
 * to fx-shadow-well on a field of any size. Its 3:1 SC 1.4.11 boundary is
 * therefore inherited, not re-derived, and cannot drift out of step. */
.lpx-content :is(.fx-control-xs,
                 .form-control-sm, .form-select-sm, .fx-control-sm,
                 .fx-control-md,
                 .form-control-lg, .form-select-lg, .fx-control-lg) {
    min-block-size: var(--fx-ctl-h);
    padding-block: var(--fx-ctl-pad-y);
    padding-inline: var(--fx-ctl-pad-x);
    font-size: var(--fx-ctl-font-size);
    border-radius: var(--fx-ctl-radius);
}

/* The hover and focus FILLS ride the local, which the state rules in section 2
 * have already set, so these two only have to win the specificity fight â€” they
 * do not restate a colour and cannot drift from the base rules. */
@media (any-hover: hover) {
    .lpx-content .form-control:hover:not(:disabled):not([readonly]),
    .lpx-content .form-select:hover:not(:disabled),
    .lpx-content textarea:hover:not(:disabled):not([readonly]),
    .lpx-content select:hover:not(:disabled) {
        background-color: var(--fx-ctl-bg);
    }
}

/* Focus BRIGHTENS AND RINGS. The outline is restated because LeptonX and several
 * vendored sheets set `outline: 0` on :focus for form controls, and under the
 * outline model that is a total loss of the indicator rather than a cosmetic
 * one. The WELL is restated with it, because a focused field must still be
 * identifiable as a field under SC 1.4.11.
 *
 * THE :not() LIST IS LOAD BEARING. A bare `.lpx-content input:focus` also
 * matches a checkbox, a radio, a range, a colour picker, a file input and every
 * button-shaped input. For the CHECKBOX, RADIO, RANGE and button-shaped inputs
 * the reason is still the original one: none of them declare the fx-ctl-*
 * locals, an undefined custom property makes the declaration reading it INVALID
 * AT COMPUTED-VALUE TIME, and `background-color: var(fx-ctl-bg)` would resolve
 * to transparent so a focused checkbox inside the app shell would lose its fill
 * entirely. The previous pass of this block had that defect.
 *
 * THE COLOUR AND FILE INPUTS ARE NOW EXCLUDED FOR A DIFFERENT REASON, and the
 * distinction matters to whoever edits this next: since sections 10.4 and 10.5
 * they DO declare the locals, so they would no longer be broken by inclusion â€”
 * they would merely be wrong. Each owns its own focus rule a few hundred lines
 * up, a swatch has no field fill to brighten, and the file input's rule is what
 * keeps its generated trigger from taking the ring twice. */
/* â•â• THE GLOW HAS TO BE RESTATED HERE TOO, AND FORGETTING IT COST A CYCLE â•â•â•
 *
 * 2026-08-29. The field focus model moved from a detached outline to a hugging
 * glow (section 2, and the token's own header in 00-tokens). That change was
 * made ONLY in section 2, at (0,2,1) â€” and this block is (0,3,0), two thousand
 * lines later. So inside `.lpx-content`, which is every ordinary page, the new
 * model was silently overwritten and the old outline kept painting; while every
 * ABP MODAL, which is appended to `body` OUTSIDE this scope, got the new glow.
 * The product had two different focus treatments depending on whether you were
 * in a dialog, which is worse than either model on its own.
 *
 * That is section Z.1's own failure shape, arriving from the other direction:
 * this block exists to harden the page against Bootstrap, and anything section 2
 * changes about the painted state MUST be mirrored here in the same edit or the
 * page keeps the old behaviour. `box-shadow` is now the third such property,
 * beside `background-color` and `border`. */
.lpx-content .form-control:focus,
.lpx-content .form-select:focus,
.lpx-content textarea:focus,
.lpx-content select:focus,
.lpx-content input:not([type="checkbox"], [type="radio"], [type="range"], [type="color"], [type="file"], [type="image"], [type="submit"], [type="button"], [type="reset"]):focus {
    background-color: var(--fx-ctl-bg);
    border: var(--fx-ctl-border);
    /* Identical expression to section 2 â€” read the fallback chain's reasoning
     * there. If these two ever disagree, section 2 is the decision and this is
     * the copy that failed to keep up. */
    box-shadow: var(--fx-ctl-shadow-focus, var(--fx-shadow-field-focus), var(--fx-ctl-shadow));
}

/* Same exclusion list, for a different reason: a checkbox draws its ring at a
 * NEGATIVE offset (section 12) so it hugs the 16px artwork rather than the 24px
 * hit box, and this selector would out-specify that and push the ring back out. */
/* The outline half of the same 2026-08-29 change, mirrored here for the same
 * reason as the box-shadow above. TRANSPARENT, NOT REMOVED: forced-colours mode
 * drops every box-shadow in the document, so the geometry stays reserved and
 * section 16 colours it back in. Deleting these two declarations would look like
 * tidying and would be an accessibility regression.
 *
 * The exclusion list is unchanged and still load-bearing: a checkbox draws its
 * ring at a NEGATIVE offset (section 12), and this selector would out-specify
 * that and push the ring back out. Checkboxes and radios keep the outline model
 * entirely â€” the glow is for things you type into. */
.lpx-content .form-control:focus-visible,
.lpx-content .form-select:focus-visible,
.lpx-content textarea:focus-visible,
.lpx-content select:focus-visible,
.lpx-content input:not([type="checkbox"], [type="radio"]):focus-visible {
    outline: var(--fx-focus-width) solid transparent;
    outline-offset: var(--fx-focus-offset);
}

/* Bootstrap paints validation as a border plus an embedded SVG background. The
 * background goes; the BORDER is ours now, so it is restated at (0,3,0) â€” high
 * enough to beat the (0,2,0) base restatement above, which would otherwise hand
 * the field back its resting `--fx-ctl-border` and erase the error boundary.
 * Scoped to the field elements themselves: `[aria-invalid="true"]` is set on
 * wrappers and grid cells too, and a bare attribute selector here would draw a
 * red box round a <div>. */
.lpx-content .form-control.is-invalid,
.lpx-content .form-select.is-invalid,
.lpx-content textarea.is-invalid,
.lpx-content select.is-invalid,
.lpx-content .input-validation-error,
.lpx-content :is(.form-control, .form-select, textarea, select, input)[aria-invalid="true"] {
    background-image: none;
    border: var(--fx-border-width-strong) solid var(--fx-color-danger-fg);
    /* The LOCAL, not fx-shadow-well outright. Section 14 deliberately leaves the
     * depth of an invalid field to whatever its resting state chose, so that a
     * disabled or readonly field that also fails validation stays flat; naming
     * the token here would have re-lit it, at a specificity nothing earlier in
     * the file can reach. */
    box-shadow: var(--fx-ctl-shadow);
}

/* Bootstrap's green valid state, suppressed to match section 14.2. */
.lpx-content .form-control.is-valid,
.lpx-content .form-select.is-valid,
.lpx-content textarea.is-valid,
.lpx-content select.is-valid {
    background-image: none;
    border: 0;
}

/* Disabled and readonly go flat: no well, because there is no depth to enter.
 *
 * THE TEXT COLOUR NOW READS THE LOCAL, AND THAT FIXES A REAL DEFECT. This rule
 * names both states in one selector list and used to force
 * fx-color-disabled-fg on both, so a READONLY field inside the app shell â€” that
 * is, every readonly field on the platform â€” rendered dimmed. Section 2 says
 * the opposite in as many words: readonly reads as INFORMATIVE, keeps full text
 * contrast, and is told apart from disabled by exactly that, because a lawyer
 * must still be able to read and copy a readonly value. Reading fx-ctl-fg lets
 * each state supply its own answer from section 2 instead of this block
 * flattening the pair into one. */
.lpx-content .form-control:disabled,
.lpx-content .form-select:disabled,
.lpx-content textarea:disabled,
.lpx-content select:disabled,
.lpx-content .form-control[readonly] {
    background-color: var(--fx-ctl-bg);
    color: var(--fx-ctl-fg);
    box-shadow: none;
}

/* The custom select trigger is not a Bootstrap class, so LeptonX does not
 * contest it today â€” but it sits in the same content scope and the same theme
 * reset reaches `.lpx-content button`. Restated for the same reason as above. */
.lpx-content .fx-select-trigger {
    min-block-size: var(--fx-ctl-h);
    padding-block: var(--fx-ctl-pad-y);
    padding-inline: var(--fx-ctl-pad-x);
    font-size: var(--fx-ctl-font-size);
    line-height: var(--fx-ctl-leading);
    background-color: var(--fx-ctl-bg);
    background-image: none;
    color: var(--fx-ctl-fg);
    border: var(--fx-ctl-border);
    border-radius: var(--fx-ctl-radius);
    box-shadow: var(--fx-ctl-shadow);
}


/* â”€â”€ Z.1) WHAT THIS BLOCK OUT-SPECIFIES, AND HAS TO HAND BACK â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 *
 * ADDED 2026-08-03. THIS IS THE PRICE OF SECTION Z AND IT WAS NOT BEING PAID.
 *
 * Every rule above is scoped `.lpx-content â€¦`, which buys a class of specificity
 * over the base cascade â€” that is the entire point of the section, and it is
 * why it wins against LeptonX. But a MEDIA QUERY ADDS NO SPECIFICITY. So every
 * lower tier in this file that restores a border by naming the control plainly
 * is beaten by this block on every page rendered inside the app shell, which is
 * every page on the platform. The section fixed a theming defect and silently
 * created two conformance ones.
 *
 * THE GENERAL SHAPE, because this will happen again: a HARDENING block that
 * out-specifies an ACCESSIBILITY tier does not degrade gracefully. It wins
 * exactly where the tier is needed and nowhere it can be seen in review.
 *
 * DEFECT 1 â€” FORCED COLOURS. SC 1.4.11, and the serious one.
 *   `.lpx-content .form-control { border: var(--fx-ctl-border) }` is (0,2,0);
 *   section 16.4's `.form-control { border: 1px solid ButtonBorder }` is (0,1,0)
 *   and `textarea` / `select` / `input` are (0,0,1) against this block's (0,1,1)
 *   and (0,2,1). The hardening block therefore won everywhere, and it resolves
 *   `--fx-ctl-border` to its resting value, which is `0`. Windows High Contrast
 *   is precisely the mode in which the fill difference, the field background and
 *   `fx-shadow-well` are ALL discarded by the user agent â€” the border is the only
 *   boundary left, and it is the only thing carrying the 3:1 identification cue.
 *   EVERY FIELD INSIDE THE APP SHELL WAS AN INVISIBLE RECTANGLE IN HIGH CONTRAST.
 *   The three `:focus`, `.is-valid` and step rules above compound it at (0,3,0).
 *   Note `.is-invalid` needs no restore: it writes a real 2px border with an
 *   author colour, and forced-colors repaints a border it can see.
 *
 * DEFECT 2 â€” PRINT. Section 17 turns a field into a value on a RULED LINE by
 *   zeroing the locals and then drawing `border-block-end`. Zeroing the locals
 *   survives this block by design â€” that is why 17 is written as locals â€” but
 *   the ruled line itself is a real declaration at (0,1,0), and this block's
 *   `border: var(--fx-ctl-border)` shorthand at (0,2,0) resets all four sides
 *   including that one. A printed case form inside the shell came out as blank
 *   space where every value should have sat on a line. On a platform whose
 *   printed output is a legal artefact that is not a cosmetic loss.
 *
 * WHY THE RESTORES LIVE HERE RATHER THAN IN 16.4 AND 17. Raising those two
 * sections to `.lpx-content` specificity would scope an accessibility tier to a
 * theme class, so a field rendered OUTSIDE the shell would silently drop out of
 * both. Restating them here at this block's own weight, immediately after the
 * rules that caused the problem, keeps the base tiers cheap and universal and
 * puts the correction where the next person to edit section Z will read it â€”
 * the same reasoning the two height restores above are written with. These
 * selectors mirror section Z's exactly; if a selector is added there, add it
 * here too.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
@media (forced-colors: active) {
    .lpx-content .form-control,
    .lpx-content .form-select,
    .lpx-content textarea,
    .lpx-content select,
    .lpx-content input:not([type]),
    .lpx-content input[type="text"],
    .lpx-content input[type="email"],
    .lpx-content input[type="password"],
    .lpx-content input[type="number"],
    .lpx-content input[type="tel"],
    .lpx-content input[type="url"],
    .lpx-content input[type="search"],
    .lpx-content input[type="date"],
    .lpx-content input[type="time"],
    .lpx-content input[type="datetime-local"],
    .lpx-content input[type="month"],
    .lpx-content input[type="week"],
    .lpx-content .fx-select-trigger,
    /* The two (0,3,0) state rules above, matched. A focused or a validated
       field must not be the one that loses its only boundary. */
    .lpx-content .form-control:focus,
    .lpx-content .form-select:focus,
    .lpx-content textarea:focus,
    .lpx-content select:focus,
    .lpx-content .form-control.is-valid,
    .lpx-content .form-select.is-valid,
    .lpx-content textarea.is-valid,
    .lpx-content select.is-valid {
        border: var(--fx-border-width) solid ButtonBorder;
    }

    /* â•â• THE FOCUS RING, AT (0,3,0), BECAUSE A MEDIA QUERY ADDS NO SPECIFICITY â•
     *
     * Section Z now paints the focused field's outline TRANSPARENT and lets the
     * box-shadow glow carry focus â€” and forced-colours drops every box-shadow in
     * the document. The restore in section 16 is written at (0,2,1) and would
     * therefore LOSE to section Z's (0,3,0) transparent outline, leaving a
     * focused field with no indicator at all in exactly the mode where that
     * matters most. The media query buys no weight; only the selector does.
     *
     * So the ring is restored a second time here, selector-for-selector against
     * section Z's focus-visible rule. Highlight rather than ButtonBorder: the
     * resting border above is already ButtonBorder, and a focus ring painted the
     * same colour as the resting stroke is not a focus ring. */
    .lpx-content .form-control:focus-visible,
    .lpx-content .form-select:focus-visible,
    .lpx-content textarea:focus-visible,
    .lpx-content select:focus-visible,
    .lpx-content input:not([type="checkbox"], [type="radio"]):focus-visible {
        outline: var(--fx-focus-width) solid Highlight;
        outline-offset: var(--fx-focus-offset);
    }
}

@media print {
    .lpx-content .form-control,
    .lpx-content .form-select,
    .lpx-content textarea,
    .lpx-content select,
    .lpx-content input:not([type]),
    .lpx-content input[type="text"],
    .lpx-content input[type="email"],
    .lpx-content input[type="password"],
    .lpx-content input[type="number"],
    .lpx-content input[type="tel"],
    .lpx-content input[type="url"],
    .lpx-content input[type="search"],
    .lpx-content input[type="date"],
    .lpx-content input[type="time"],
    .lpx-content input[type="datetime-local"],
    .lpx-content .fx-select-trigger,
    /* THE (0,3,0) STATE RULES, MATCHED â€” AND THEY WERE MISSING UNTIL 2026-08-03.
       This is DEFECT 2 recurring one weight up, inside the very block written to
       answer it. The forced-colours branch immediately above already carries
       these two selectors and says so in as many words; the print branch was
       written from the (0,2,0) list alone and therefore lost to exactly the
       rules the note over it identifies:

         `.lpx-content .form-control:focus`     (0,3,0) sets `border:
                                                var(--fx-ctl-border)`, which is 0
                                                in print, so all four sides go
         `.lpx-content .form-control.is-valid`  (0,3,0) sets `border: 0` outright

       Either one erases the ruled line this block exists to redraw, and a
       printed case form came out with blank space where the value should sit on
       a line â€” the same loss, on the same platform, for the same reason, half
       fixed. `.is-invalid` is deliberately absent: it writes a real 2px border
       with an author colour at (0,3,0), so the field keeps a visible boundary on
       paper and restating it here would only take that boundary away.

       IF A SELECTOR IS ADDED TO SECTION Z, ADD IT TO BOTH BRANCHES HERE. The
       forced-colours list above already says this; it applies to this list too,
       and the fact that the two lists drifted apart is what produced the
       defect. */
    .lpx-content .form-control:focus,
    .lpx-content .form-select:focus,
    .lpx-content textarea:focus,
    .lpx-content select:focus,
    .lpx-content .form-control.is-valid,
    .lpx-content .form-select.is-valid,
    .lpx-content textarea.is-valid,
    .lpx-content select.is-valid {
        /* Section 17's locals already flatten everything else through this
           block, because it reads them. Only the RULED LINE has to be redrawn,
           because it is the one declaration in 17 that is not a local. */
        border: var(--fx-ctl-border);
        border-block-end: var(--fx-border-width) solid currentColor;
    }
}


/* ── THE FILE FIELD (frihat-file-field.js, 2026-10-09) ─────────────────────
 * A native file input paints its button and its "no file" line in the
 * browser's own language. The script wraps every visible one: the input stays
 * in the document, visually hidden but focusable by script and still owning
 * the form value, and an Arabic button plus the chosen file's name stand in
 * its place. Semantic tokens only, so all sixteen themes follow. */
.fx-file-field {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fx-space-2) var(--fx-space-3);
    min-inline-size: 0;
}

.fx-file-field > .fx-file-field-input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.fx-file-field-name {
    min-inline-size: 0;
    overflow-wrap: anywhere;
    font-size: var(--fx-text-sm);
    color: var(--fx-color-text-subtle);
}
