registry:lib · Engines & Theme
jx-pure — the componentless face
One stylesheet, the whole jixoai face, zero JS. Mount the jx-pure class on any DOM and the subtree's BARE native elements get the law — inspired by Pico CSS (classless element defaults) and daisyUI (semantic class vocabulary). No framework, no build step, no jixoai-ui knowledge: plain HTML in, jixoai out. The opt-in class vocabulary from the former native-form sheet rides along verbatim (Part A), so the Tier-2 components consume the same file.
install
Getting started
jx-pure consumes the token custom properties, so the token sheet comes first. Two link tags and one class — that is the entire runtime. It also drops into any CustomElement's shadow root: import the same two sheets from the shadow <style> (document CSS never crosses the shadow boundary).
# the componentless face — one css, zero js
npx jixoai-ui add jx-pure<!-- tokens first, then the face -->
<link rel="stylesheet" href="jixoai.css" />
<link rel="stylesheet" href="jx-pure.css" />
<!-- mount the class anywhere — the subtree's bare HTML is jixoai now -->
<main class="jx-pure">
<h1>Static page</h1>
<p>No build. No framework. No JS.</p>
<form>
<label for="q">search</label>
<input id="q" type="search" placeholder="grep…" />
<button type="submit">go</button>
</form>
</main>
<!-- dark: the token sheet's class, on the root or any ancestor -->
<html class="dark">
…
</html>
<!-- scoped light island inside a dark page -->
<div class="jx-light jx-pure">…stays light…</div>demo
Typography
Headings, prose, quotes, code, marks and rules — the document-flow elements preflight usually strips, restored with the jixoai law: mono-first fonts, 1px var(--border) edges, muted-foreground for the secondary voice. Everything below is BARE HTML inside a single .jx-pure div — view source, there is not one utility class in the demo.
jx-pure · typography
Headings, prose, quotes, code, marks and rules — bare HTML inside one .jx-pure div. The drawer's usage file is this demo's exact markup; the css file beside it is the real registry copy this site runs.
Heading level three
A paragraph of ordinary copy. The quick brown fox jumps over the lazy dog while strong and small keep their voices — a primary link underlines on hover, and inline code sits in a muted box. Press ⌘K to open the palette.
The platform already built the semantics — the separator, the quote, the term list. jx-pure only paints them.
const law = 'one stylesheet, zero js';
document.body.classList.add('jx-pure'); Marked text rides the secondary hue at 45% — a token mix, never a hardcoded yellow.
Below the rule, the document keeps flowing.
/**
* jx-pure — the face of jixoai-ui (registry/files/theme/jx-pure.css).
*
* V3 (css-laws, 2026-08-28): the native form-control laws are
* SINGLE-SOURCED as typed TS objects in packages/css-laws/src/laws.
* THIS file carries two GENERATED projections of that source (the
* @apply chain is retired — TW4 dev did not reliably emit complex
* utilities onto element selectors):
* Part A slot — the Tier-2 opt-in classes (.jx-control, .jx-slider,
* …), unlayered by design (they beat layered utilities)
* Part B slot — the bare-element defaults under :where(.jx-pure),
* inside this sheet's @layer components
* Regenerate after editing laws: npx tsx packages/css-laws/src/build.ts
* Non-form-control face laws (typography, links, buttons, fieldset,
* details, lists, tables, progress, figure, validation matrix, scope
* law) remain face-authored below.
*
* A · opt-in classes = GENERATED alias slot (css-laws)
* B · element defaults = GENERATED face slot (css-laws) + face-authored laws
* C · degradation laws (face-owned transitions only)
* D · auto-dark (GENERATED by scripts/gen-jx-auto-dark.mjs)
*
* Scope law: .jx-pure is a subtree wrapper — it never reaches into
* shadow roots (CustomElements must @import this sheet inside their
* own shadow style). dialog/popover/tooltip are Tier-2 territory.
*/
/* =====================================================================
A · OPT-IN CLASSES — @apply applications of the standard layer
(the declarations live once in jixoai.css; these selectors only
bind them to the opt-in vocabulary)
===================================================================== */
/* opt-in classes = GENERATED applications of the standard layer
(the declarations live once in packages/css-laws/src/laws; these
selectors bind them to the opt-in vocabulary — Tier-2, unlayered
by design: they beat layered utilities) */
/* @jixoai/css-laws:begin:jx-html-alias — GENERATED, do not edit (source: packages/css-laws/src/laws) */
.jx-slider {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
.jx-slider::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider:dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
.jx-slider[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
.jx-slider:focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
.jx-slider:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-color-swatch {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
.jx-color-swatch::-webkit-color-swatch-wrapper {
padding: 0;
}
.jx-color-swatch::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
.jx-color-swatch::-moz-color-swatch {
border: 0;
border-radius: 0;
}
.jx-tgroup {
corner-shape: var(--corner-shape, bevel);
display: inline-flex;
width: fit-content;
flex-wrap: wrap;
overflow: hidden;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--card);
box-shadow: var(--shadow-2xs);
}
.jx-tgroup> label {
display: inline-flex;
align-items: center;
min-block-size: var(--jx-hit, 2.5rem);
padding-block: calc((var(--jx-hit, 2.5rem) - var(--jx-line, 1.25rem)) / 2);
padding-inline: var(--jx-inset, 0.75rem);
font-family: var(--font-nav);
font-size: var(--jx-text, 0.8125rem);
line-height: var(--jx-line, 1.25rem);
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted-foreground);
background-color: transparent;
border-inline-end: 1px solid var(--border);
cursor: pointer;
user-select: none;
transition: color 150ms ease-out, background-color 150ms ease-out;
}
.jx-tgroup> label:last-child {
border-inline-end: 0;
}
.jx-tgroup> label:not(:has(input:disabled)):hover {
color: var(--foreground);
}
.jx-tgroup> label:has(input:checked) {
background-color: var(--primary);
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:checked):not(:has(input:disabled)):hover {
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-tgroup> label:has(input:disabled) {
cursor: not-allowed;
opacity: 0.45;
}
.jx-tgroup> label > input {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.jx-tgroup[data-chrome='bare'] {
border: 0;
background: transparent;
box-shadow: none;
border-radius: 0;
overflow: visible;
}
.jx-tgroup[data-chrome='bare'] > label {
border-inline-end: 0;
flex: 1 1 auto;
justify-content: center;
}
.jx-tgroup[data-chrome='bare'] > label:not(:has(input:disabled)):hover {
color: var(--foreground);
background-color: color-mix(in oklab, var(--muted) 55%, transparent);
}
@media (prefers-reduced-motion: reduce) {
.jx-tgroup> label {
transition: none;
}
}
.jx-control {
box-sizing: border-box;
display: block;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding: var(--jx-gap, 0.5rem) var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font-size: var(--jx-text, 0.875rem);
color-scheme: light;
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control:focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
.jx-control:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-control[aria-invalid='true'] {
border-style: dashed;
border-color: var(--error);
color: var(--error);
}
.jx-control[aria-invalid='false'] {
border-color: var(--primary);
}
.jx-control::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control[type='email'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
.jx-control {
transition: none;
}
}
.jx-control-shell {
box-sizing: border-box;
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
font-size: var(--jx-text, 0.875rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
box-shadow: var(--shadow-well);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control-shell:has(> .jx-html-clear:last-child) {
padding-inline-end: 0;
}
.jx-control-shell:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control-shell:has(:focus) {
border-color: var(--ring);
}
.jx-control-shell:has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-control-shell:has([aria-invalid='true']), .jx-control-shell.jx-invalid {
border-style: dashed;
}
.jx-control-shell:has(:disabled) {
border-color: var(--muted);
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
.jx-control-shell {
transition: none;
}
}
.jx-control-lane {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
padding: 0;
outline: none;
background: transparent;
color: var(--foreground);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
}
.jx-control-lane::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control-lane::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control-lane[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control-lane[type='email'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
/* @jixoai/css-laws:end:jx-html-alias */
.jx-control-shell.jx-slotted {
padding-inline: var(--jx-inset, 0.75rem);
}
.jx-control-shell .jx-control-lane {
padding-inline: 0;
}
.jx-field {
display: flex;
flex-direction: column;
gap: var(--jx-stack, 0.5rem);
width: 100%;
min-width: 0;
}
.jx-label {
font-family: var(--font-nav);
/* secondary-text is a density ROLE (density-adoption §3): the label
* tracks the ambient scope instead of a fixed 11px (2026-08-29) */
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
cursor: pointer;
}
.jx-error {
display: flex;
align-items: center;
gap: 0.25rem;
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--destructive);
}
.jx-error-mark {
font-weight: bold;
}
/* the shell carries NO chrome itself (final-check ruling): the box
* chrome — border AND fill — lives on a ::before BAND whose height
* matches the -webkit-color-swatch-wrapper (the actual color chip's
* lane). 2026-08-29: the fill moved OFF the shell — an element-painted
* background leaks a full-height rectangle that ears out above/below
* the band on any surface where ambient ≠ --background (cards,
* panels, dark); the band now fills itself.
*
* GEOMETRY LAW (final-check ruling 2, the checkbox/range precedent):
* the chip is a LOCKED size-and-ratio block — height = the hit lane,
* aspect 7:4 (≈4.8rem at the 2.75rem hit — visually balanced, NOT a
* literal width), and the shell is its own SIZE CONTAINER: every
* internal geometry derives from 100cqh, so a density change (or a
* consumer height override) scales the whole chip proportionally —
* the swatch circle, the band, the pill radius, the glyph. The hit
* token sets ONLY the height; nothing else reads it. */
.jx-color-shell {
display: flex;
flex: none;
/* the shell's internal ladder (swatch z1, pipette ::after z2, the
custom-picker overlay z1) is COMPONENT-PRIVATE: container-type
does NOT establish a stacking context (measured, the isolation
clause 2026-09-09), so the shell roots it explicitly — the
deferred class-(a) tail cleared */
isolation: isolate;
/* fit-content protects the ratio-derived width from stretch (grid
tracks, block flow) while aspect-ratio + the locked height keep
it the chip's intrinsic 7:4 */
width: fit-content;
height: var(--jx-hit, 2.5rem);
aspect-ratio: 7 / 4;
container-type: size;
cursor: pointer;
position: relative;
transition: box-shadow 150ms ease-out;
}
.jx-color-shell::before {
content: '';
position: absolute;
inset-inline: 0;
inset-block: calc(100cqh / 6);
border: 1px solid var(--border);
background: var(--background);
pointer-events: none;
corner-left-shape: round;
/* band height = 100cqh − 2×(100cqh/6) = 100cqh × 2/3 — half of it
is the true-semicircle pill radius (no clamp hack) */
border-top-left-radius: calc(100cqh / 3);
border-bottom-left-radius: calc(100cqh / 3);
corner-right-shape: bevel;
/* the right radius rides the SAME cq quantum as the band inset
(100cqh/6 ≈ 8px at the default hit — was var(--radius, 8px),
which froze while every other edge scaled with the container;
B4: no internal dimension outside cq units) */
border-top-right-radius: calc(100cqh / 6);
border-bottom-right-radius: calc(100cqh / 6);
}
.jx-color-expand {
/* both dimensions definite → aspect-ratio yields; the chip keeps
its locked height across the full row.
FLEX PARTICIPATION is re-opened here on purpose: the base shell's
flex:none protects the COMPACT chip, but it also beats any layered
flex utility (this zone is unlayered) — so width:100% alone would
size against the WHOLE flex container and overflow any sibling
(the Tier-1 demo row, 2026-08-29: 77+12+329 > 329). grow reclaims
the full row, shrink shares it; block flow is untouched. */
width: 100%;
flex: 1 1 auto;
}
.jx-color-shell:has([aria-invalid='true'])::before,
.jx-color-shell.jx-invalid::before {
border-style: dashed;
}
.jx-color-shell .jx-color-swatch {
position: relative;
z-index: 1;
flex: none;
/* the chip lane = the container's full height; the swatch circle
inside sizes from the input's own padding (also cqh-relative) */
width: 100cqh;
height: auto;
align-self: stretch;
border: 0;
border-inline-end: 1px solid var(--border);
padding: calc(100cqh / 6);
}
.jx-color-shell .jx-color-swatch:focus-visible {
outline: none;
}
/* clear button: SUPERSEDED by jx-html-clear in the standard layer */
/* @jixoai/css-laws:begin:jx-icon-vocab — GENERATED, do not edit (source: packages/css-laws/src/icon-vocab) */
/* the pipette glyph — an ICON SLOT on the WRAPPER (input[type=color]
* is a replaced element whose ::after is unreliable across engines;
* the label wrapper is non-replaced and paints reliably) */
.jx-color-shell::after {
content: '';
position: absolute;
/* decorative carrier (the law's TRANSIENT INK family) + a ladder
rung — z2 orders against the swatch z1 INSIDE the shell, whose
own isolation: isolate roots the ladder (the isolation clause,
2026-09-09; the shell rule lives in the hand zone above) */
z-index: 2;
/* proportional optics: glyph ≈ 36% of the lane, end inset ≈ 27% —
scale with the container, not with font size */
inset-inline-end: calc(100cqh * 0.27);
top: 50%;
width: calc(100cqh * 0.36);
height: calc(100cqh * 0.36);
translate: 0 -50%;
color: var(--muted-foreground);
background-color: currentColor;
-webkit-mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
pointer-events: none;
}
.jx-color-shell:hover::after {
color: var(--foreground);
}
/* the color-picker chevron — an ICON SLOT (mask, currentColor themes) */
.jx-color-picker-chevron {
display: block;
width: 0.75rem;
height: 0.75rem;
background-color: currentColor;
-webkit-mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
}
/* =====================================================================
Icon vocabulary — the mask/currentColor law. One alpha-only URI per
glyph; the encoded stroke %23000 is an ALPHA SOURCE ONLY. The INK
variants (calendar/clock/valid/invalid) serve UA-shadow pseudos that
reject author mask paint; .dark flips them to %23fff, .jx-light back.
===================================================================== */
@layer theme {
:root {
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* THEME-SCOPED placeholder (canvas bug, Owner 2026-09-04 — same law
as the variant-grammar slots in jixoai.css): custom properties
substitute their var() at the DECLARING element — a :root-only
--jx-placeholder handed every descendant the root's
already-substituted mix, so a scoped .dark/.jx-light
(component-canvas stage, terminal-card, print) flipping
--foreground/--background never re-flipped the placeholder ink
with it. The selector list re-declares the slot ON each theme
scope: one declaration point, zero duplicates */
:root,
.jx-light,
.dark {
--jx-placeholder: color-mix(in oklab, var(--foreground) 40%, var(--background));
}
}
.dark {
/* the author-painted icon set flips to white ink in dark (the
-ink quartet's law extended to the plain slots the input/select
laws consume — black alpha URIs vanish on the dark token sheet) */
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
.jx-light {
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* @jixoai/css-laws:end:jx-icon-vocab */
/* =====================================================================
The zero-class STRUCTURAL input group: a label wrapping a text-like
control AND at least one span composes into the shell — the label
takes the box law, the spans ride as prefix/suffix cells, the
control goes chromeless. NO opt-in class needed.
===================================================================== */
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) {
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
padding-inline: var(--jx-inset, 0.75rem);
cursor: text;
transition: box-shadow 150ms ease-out;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):hover {
box-shadow: var(--shadow-2xs);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > span {
display: inline-flex;
align-items: center;
flex: none;
font-size: var(--jx-text, 0.875rem);
color: var(--muted-foreground);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > input {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
outline: none;
background: transparent;
color: var(--foreground);
font: inherit;
font-size: var(--jx-text, 0.875rem);
padding-inline: 0;
}
/* =====================================================================
Switch size modifiers (face-owned; the standard utility carries the
density-alias default, these opt into explicit sizes)
===================================================================== */
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-sm:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-sm input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 2rem;
--jx-toggle-track: 1.25rem;
--jx-toggle-knob: 0.75rem;
}
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-lg:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-lg input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 3rem;
--jx-toggle-track: 1.5rem;
--jx-toggle-knob: 1.25rem;
}
/* =====================================================================
Bare color input: the locked square standalone (without a .jx-color-
shell wrapper)
===================================================================== */
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: calc(var(--jx-hit, 2.5rem) - 2px);
padding: 2px;
}
/* =====================================================================
Reduced-motion law: the sheet's face-owned transitions neutralize.
===================================================================== */
@media (prefers-reduced-motion: reduce) {
.jx-control,
.jx-control-shell,
.jx-color-shell {
transition: none;
}
}
/* =====================================================================
B · ELEMENT DEFAULTS — the .jx-pure subtree face.
Every rule rides :where(.jx-pure) so the scope class contributes
ZERO specificity inside @layer components: Tailwind utilities
(utilities layer) and any unlayered author css override these
cheaply, and non-Tailwind static consumers override with plain
css. Colors come from tokens or currentColor ONLY — no hardcoded
paint survives a theme flip.
===================================================================== */
@layer components {
/* ---- B0 · the scope root: color-scheme follows the theme classes
the token sheet owns. color-scheme INHERITS — one declaration
themes every native picker, scrollbar and form control in the
subtree: light under :root, dark under .dark (ancestor or self),
forced light under .jx-light. */
:where(.jx-pure):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
/* density adoption (native-contract-fusion Phase 5): the scope
root rides the density interface's text/leading aliases (the
typography LADDER above keeps its fixed steps — declared gap) */
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.6);
}
:where(.dark) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.dark):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
:where(.jx-light) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.jx-light):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
}
/* =====================================================================
B1 · Typography — documented rem steps (the repo ships no
typography size tokens; these literals ARE the scale until a
token ruling lands — do not scatter new sizes elsewhere). The
flow margins are EXPLICIT because preflight zeroes them: a
Tailwind host without this block would render wall-of-text prose.
===================================================================== */
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6):not(.no-jx-pure, .no-jx-pure *) {
margin: 1.5em 0 0.6em;
font-weight: 700;
line-height: 1.25;
color: var(--foreground);
}
:where(.jx-pure) h1:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.875rem;
}
:where(.jx-pure) h2:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.5rem;
}
:where(.jx-pure) h3:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.25rem;
}
:where(.jx-pure) h4:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.125rem;
}
:where(.jx-pure) :where(h5, h6):not(.no-jx-pure, .no-jx-pure *) {
font-size: 1rem;
}
:where(.jx-pure) :where(p, ul, ol, dl, blockquote, pre, table, hr):not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
}
:where(.jx-pure) p:not(.no-jx-pure, .no-jx-pure *) {
line-height: 1.6;
}
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6) :where(p, ul, ol, dl, blockquote, pre, table):first-child:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0;
}
:where(.jx-pure) small:not(.no-jx-pure, .no-jx-pure *) {
font-size: 0.8125rem;
color: var(--muted-foreground);
}
:where(.jx-pure) :where(strong, b):not(.no-jx-pure, .no-jx-pure *) {
font-weight: 700;
}
:where(.jx-pure) blockquote:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-start: 0.875rem;
border-inline-start: 1px solid var(--border);
color: var(--muted-foreground);
}
:where(.jx-pure) :where(code, kbd, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.1em 0.4em;
border: 1px solid var(--border);
background: var(--muted);
font-family: var(--font-mono);
font-size: 0.8125rem;
}
:where(.jx-pure) kbd:not(.no-jx-pure, .no-jx-pure *) {
/* the key cap is ENGRAVED, not lifted (F-2, adversarial-review
2026-09-02 — Owner kbd ruling): --shadow-engrave inset, the
elevation grammar's engrave tier, unified with the registry kbd
component (shadow-engrave). The old `0 1px 0 var(--border)`
lifted-edge dialect is retired — one kbd face across the bare
element and the component. */
box-shadow: var(--shadow-engrave);
}
:where(.jx-pure) pre:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.75rem 1rem;
border: 1px solid var(--border);
background: var(--background);
overflow: auto;
font-family: var(--font-mono);
font-size: 0.8125rem;
line-height: 1.55;
}
/* the code-in-pre lane drops its inline box — the pre owns the box */
:where(.jx-pure) pre :where(code, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0;
border: 0;
background: transparent;
font-size: inherit;
}
:where(.jx-pure) mark:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.05em 0.25em;
background: color-mix(in oklab, var(--secondary) 45%, var(--background));
color: var(--foreground);
}
:where(.jx-pure) hr:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 1.5rem;
border: 0;
border-top: 1px solid var(--border);
}
/* =====================================================================
B2 · Links — the site link law (press-button link variant):
primary text, no underline at rest, underline on hover. Nav links
read as chrome, not prose: foreground at rest, primary + underline
as the hover cue.
===================================================================== */
:where(.jx-pure) a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-underline-offset: 4px;
}
:where(.jx-pure) a:hover:not(.no-jx-pure, .no-jx-pure *) {
text-decoration-line: underline;
}
:where(.jx-pure) nav a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--foreground);
}
:where(.jx-pure) nav a:hover:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-decoration-line: underline;
}
/* =====================================================================
B3 · Buttons — the .jx-press physics restated element-scoped
(hover grows the token shadow + bg-muted; active presses +1px
into the page with the *-press twin — same variable contract,
no WAAPI, no second geometry law). .jx-button is the EXPLICIT
channel for link-look buttons (Codex D2: never auto-style
a[role=button] — CSS cannot add command semantics). Focus is
deliberately NOT set here: the host's focus law owns it (site
base layer paints a/button; static pages keep the UA ring).
===================================================================== */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *) {
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.375rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 1rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
line-height: 1.45;
text-decoration: none;
cursor: pointer;
box-shadow: var(--jx-press-shadow, var(--shadow-xs));
transition:
translate 150ms ease-out,
box-shadow 150ms ease-out,
background-color 150ms ease-out,
border-color 150ms ease-out,
color 150ms ease-out;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):hover:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
box-shadow: var(--jx-press-shadow-hover, var(--shadow-sm));
}
/* :active LAST — at equal specificity the later rule wins the hover pose */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: 1px 1px;
box-shadow: var(--jx-press-shadow-active, var(--shadow-sm-press));
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
cursor: not-allowed;
box-shadow: none;
}
/* =====================================================================
B4+B5 · form controls = @apply applications of the standard
layer (the 13-type allowlist rides each selector; the number lane
keeps the PLATFORM stepper by sharing jx-html-input; checkbox
excludes [role=switch] so the switch gets its own utility) ----- */
/* GENERATED between the markers (css-laws V3): the bare-element
defaults — same declaration source as the .jx-html-* classes,
serialized as element-default rules under :where(.jx-pure) */
/* @jixoai/css-laws:begin:jx-html-face — GENERATED, do not edit (source: packages/css-laws/src/laws) */
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-textarea-min, 5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
height: auto;
resize: vertical;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
--jx-icon-chevron-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
cursor: pointer;
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):disabled, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
@supports not selector(::-moz-range-progress) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
background-image: var(--jx-icon-chevron, var(--jx-icon-chevron-svg));
background-position: right var(--jx-inset, 0.75rem) center;
background-size: var(--jx-icon, 1.25rem);
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
filter: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]) {
min-height: 5.75rem;
padding-block: 0.375rem 0.5rem;
cursor: default;
background-image: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
cursor: pointer;
transition: background-color 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate::before {
opacity: 1;
transform: rotate(0deg);
clip-path: polygon(10% 40%, 10% 60%, 45% 60%, 55% 60%, 90% 60%, 90% 40%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked, :where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate {
background: var(--primary);
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 50%;
background: var(--background);
cursor: pointer;
transition: border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
content: none;
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::after {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
border-radius: 50%;
background: var(--primary);
transform: scale(0);
transition: transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::after {
transform: scale(1);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--background);
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
position: relative;
width: var(--jx-toggle-width, 2.5rem);
height: var(--jx-toggle-track, 1.5rem);
margin: 0;
flex: none;
padding: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
border: 0;
box-shadow: 0 0 0 1px var(--border) inset;
border-radius: calc(infinity * 1px);
background: var(--muted);
cursor: pointer;
transition: background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
inset-block: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inset-inline-start: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inline-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
block-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
border-radius: calc(infinity * 1px);
border: var(--jx-toggle-knob-border, 1px) solid var(--jx-toggle-knob-border-color, var(--primary));
background: var(--background);
transform: translateX(0);
transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1), background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), border-color 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
transform: translateX(calc(var(--jx-toggle-width, 2.5rem) - var(--jx-toggle-track, 1.5rem)));
background: var(--primary-foreground);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
box-shadow: 0 0 0 1px var(--primary) inset;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)) {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch-wrapper {
padding: 0;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-moz-color-swatch {
border: 0;
border-radius: 0;
}
/* @jixoai/css-laws:end:jx-html-face */
/* ---- B6 · label / fieldset / legend (face-owned; not form-
control law — the one-opacity-owner disabled law) -------------
===================================================================== */
:where(.jx-pure) label:not(.no-jx-pure, .no-jx-pure *) {
cursor: pointer;
}
:where(.jx-pure) fieldset:not(.no-jx-pure, .no-jx-pure *) {
min-width: 0;
margin-block: 0.75rem;
padding: 0.875rem 1rem 1rem;
border: 1px solid var(--border);
border-radius: 0;
}
:where(.jx-pure) fieldset:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* ONE opacity owner per subtree (Codex review A3): the group dims to
.5 and the controls inside stay at 1 — two stacked .5 layers
composite to ~.25 and the contrast collapses */
:where(.jx-pure) fieldset:disabled :where(input, textarea, select, button):not(.no-jx-pure, .no-jx-pure *) {
opacity: 1;
cursor: not-allowed;
}
:where(.jx-pure) legend:not(.no-jx-pure, .no-jx-pure *) {
padding-inline: 0.5rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* =====================================================================
B7 · details / summary — document-flow disclosure ONLY (dialog /
popover / tooltip stay Tier-2, Codex D3). Static marker swap, no
open/close animation (progressive enhancement deferred); the
visible focus ring is never replaced by the marker.
===================================================================== */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *) {
display: flex;
align-items: center;
gap: 0.625rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
font-size: 0.875rem;
list-style: none;
cursor: pointer;
transition:
border-color 150ms ease-out,
box-shadow 150ms ease-out;
}
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::-webkit-details-marker {
display: none;
}
/* the marker: a bordered square holding + / − (static swap) */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '+';
box-sizing: border-box;
display: grid;
place-items: center;
width: 1.125rem;
height: 1.125rem;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--muted-foreground);
font-family: var(--font-nav);
font-size: 12px;
line-height: 1;
}
:where(.jx-pure) details[open] > summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '−';
}
:where(.jx-pure) summary:hover:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--primary); /* leans like the checkbox border */
}
:where(.jx-pure) summary:focus-visible:not(.no-jx-pure, .no-jx-pure *) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) details > * + *:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.5rem;
}
/* =====================================================================
B8 · lists / dl — restore the document-flow markers preflight
removes (classless parity) and theme them; nav's link law lives
in B2.
===================================================================== */
:where(.jx-pure) ul:not(.no-jx-pure, .no-jx-pure *) {
list-style: disc;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) ol:not(.no-jx-pure, .no-jx-pure *) {
list-style: decimal;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) li:not(.no-jx-pure, .no-jx-pure *)::marker {
color: var(--muted-foreground);
}
:where(.jx-pure) dl:not(.no-jx-pure, .no-jx-pure *) {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.375rem 1rem;
}
:where(.jx-pure) dt:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
:where(.jx-pure) dd:not(.no-jx-pure, .no-jx-pure *) {
margin: 0;
}
/* =====================================================================
B9 · Tables — the bordered grid law.
===================================================================== */
:where(.jx-pure) table:not(.no-jx-pure, .no-jx-pure *) {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
:where(.jx-pure) caption:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.375rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
caption-side: bottom;
text-align: start;
}
:where(.jx-pure) :where(th, td):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
text-align: start;
}
:where(.jx-pure) th:not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
font-family: var(--font-nav);
font-size: 11px;
font-weight: 400;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
white-space: nowrap;
}
:where(.jx-pure) tbody tr:hover:not(.no-jx-pure, .no-jx-pure *) {
background: color-mix(in oklab, var(--muted) 26%, transparent);
}
/* =====================================================================
B10 · progress / meter / output (Owner completion round, 2026-08-24:
the Codex D6 deferral is overruled — the contracts exist now).
progress: the range-track geometry (8px bordered box, primary
fill); indeterminate trades the fill for a sliding stripe, fully
static under reduced motion. meter: the same box with the
SEMANTIC token mapping — optimum=primary, suboptimal=secondary,
even-less-good=destructive (no hardcoded traffic lights). output:
the mono result lane. Engine pseudos live in SEPARATE rules (the
R1 law: a shared -moz list is dropped whole by Chromium).
===================================================================== */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *) {
display: block;
box-sizing: border-box;
width: 100%;
height: 0.5rem; /* the 8px track family (incl. borders) */
margin: 0;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
appearance: none;
-webkit-appearance: none;
overflow: hidden;
}
:where(.jx-pure) progress:disabled:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* chromium: the track pseudo + the value pseudo */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-bar {
background: var(--background);
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-value {
background: var(--primary);
transition: width 150ms ease-out;
}
/* indeterminate: no percent exists — a muted stripe slides across.
The stripe rides the ELEMENT's own background, never the UA
pseudos: engines reject author paint/animation on progress
pseudos exactly like the number spinners (Codex r4 R4-1 — the
pseudo path compiled but never animated). Part C parks it under
reduced motion. */
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *) {
background:
linear-gradient(in oklab, var(--muted), var(--muted)) 0 0 / 40% 100% no-repeat,
var(--background);
animation: jx-progress-slide 1.2s linear infinite;
}
/* firefox: the element is the track; the bar pseudo is the value */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: var(--primary);
}
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: transparent; /* the element's stripe owns the paint */
}
/* meter: the semantic three-state fill (token-mapped, monochrome law) */
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-bar {
background: var(--background);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-optimum-value {
background: var(--primary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-suboptimum-value {
background: var(--secondary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-even-less-good-value {
background: var(--destructive);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--primary);
}
:where(.jx-pure) meter:-moz-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--secondary);
}
:where(.jx-pure) meter:-moz-sub-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--destructive);
}
/* the stripe keyframes live OUTSIDE the layer's rule bodies… they
are defined once here (keyframes are global; the jx- prefix keeps
the namespace) — declared at the layer's end so both engine rules
above can reference them */
}
@keyframes jx-progress-slide {
from {
background-position: -40% 0, 0 0;
}
to {
background-position: 140% 0, 0 0;
}
}
@layer components {
/* output: the calculation result lane — mono, foreground, inline */
:where(.jx-pure) output:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-mono);
font-size: 0.875rem;
color: var(--foreground);
}
/* =====================================================================
B11 · figure / media — the documentation flow. figure carries the
flow margin + the bordered plate; figcaption rides the caption
law (nav font, small caps, muted, below). Media never overflows
its lane.
===================================================================== */
:where(.jx-pure) :where(img, video):not(.no-jx-pure, .no-jx-pure *) {
max-width: 100%;
height: auto;
}
:where(.jx-pure) figure:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.375rem;
max-width: 100%;
}
:where(.jx-pure) figure > :where(img, video, svg, pre, table):not(.no-jx-pure, .no-jx-pure *) {
border: 1px solid var(--border);
}
:where(.jx-pure) figcaption:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* ---- B13 · switch = @apply application (the ONE input law;
[role=switch] discriminates it from the checkbox) ------------- */
/* the label posture: a wrapping label dims with its input */
:where(.jx-pure) label:has(> input[type='checkbox'][role='switch']):not(.no-jx-pure, .no-jx-pure *) {
display: inline-flex;
align-items: center;
gap: var(--jx-gap, 0.5rem);
cursor: pointer;
user-select: none;
min-block-size: var(--jx-hit, 2.5rem);
&:has(input:disabled) {
cursor: not-allowed;
opacity: 0.5;
}
}
/* =====================================================================
B14 · validation states — the Pico state matrix on the SEMANTIC
palette (openspec D5): aria-invalid='false' leans --success ('✓'
ink + success border + success hover lean); aria-invalid='true'
flips every accent to --error (dashed lanes + '!' ink, checked
fills, the radio DOT, switch track, range fill + thumb).
--destructive is NOT used here — it stays the monochrome
inversion pair for destructive actions. Native :invalid stays
deliberately unhooked (no empty-required surprises).
===================================================================== */
/* lanes: border-color states + the ink glyphs */
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
background-image: var(--jx-icon-invalid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: 2rem;
background-image: var(--jx-icon-valid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
/* checkbox / radio: the checked accent flips to error */
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:indeterminate:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::after {
background: var(--error-foreground);
}
:where(.jx-pure) input[type='checkbox'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success); /* the valid lean */
}
/* switch: the checked track flips */
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::before {
border-color: transparent;
}
/* range: fill + thumb flip */
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
--jx-slider-fill-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-webkit-slider-thumb {
border-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-moz-range-thumb {
background: var(--error);
}
}
/* =====================================================================
B12 · the reverse scope — .no-jx-pure (Owner third revision,
2026-08-24): the r8/r9 `all: revert !important` hatch was too
violent — it also rolled back the HOST's own utilities and inline
styles. Every face rule now carries the exclusion on its subject:
:not(.no-jx-pure, .no-jx-pure *) — an element that IS, or lives
inside, a no-jx-pure subtree never receives the face; everything
the host authored there is untouched. Part A opt-in classes still
work inside islands (author intent, not face paint). INHERITED
properties (color-scheme, custom property tokens) keep flowing
through islands from ancestors — the exclusion is element-level
paint, never a war against the page's theme or the host.
=====================================================================
*/
/* =====================================================================
C · DEGRADATION LAWS — motion and forced colors.
===================================================================== */
/* Reduced motion: FULL STILLNESS, not zero-duration animation (Codex
review B): every Part B transition goes none AND the interactive
displacements (the press translate, the thumb press transform) are
pinned back to their rest poses so nothing ever moves. */
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) :where(textarea, select):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
/* engine pseudos NEVER share a selector list — a non-forgiving list
with an unknown -moz pseudo is dropped WHOLE by Chromium (Codex
r2 R1); one rule per engine surface */
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
/* the indeterminate stripe parks: element animation off (the
authored -moz pseudo animation is likewise killed — one rule per
surface, and the -moz one stands alone) */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *) {
animation: none;
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
animation: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
:where(.jx-pure) input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
transition: none;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: none;
}
}
/* Forced colors (Windows High Contrast & friends): the custom-painted
controls revert to appearance:auto so the SYSTEM palette and glyphs
speak — author paint would flatten into the forced canvas and lose
the checked/unchecked distinction entirely. Box laws (borders,
outlines) survive: forced-colors keeps author borders as system
colors. The opt-in select ALSO drops its gradient chevron or the
restored platform arrow would double up with the leftover paint. */
@media (forced-colors: active) {
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='range']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='color']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select:not(.no-jx-pure, .no-jx-pure *) {
appearance: auto;
-webkit-appearance: auto;
background-image: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before,
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
content: none;
}
}
/* ==== BEGIN GENERATED · jx-auto-dark — scripts/gen-jx-auto-dark.mjs (do not hand-edit) ==== */
/* Derived 1:1 from jixoai.css's .dark block (single source). The gate
rides :where() so the whole variant stays maximally overridable; it
never fires where an explicit .dark already owns the theme, nor
inside .jx-light islands. Mount: <html class="jx-pure jx-auto-dark"> */
@media (prefers-color-scheme: dark) {
:where(.jx-auto-dark):not(.dark, .jx-light *) {
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--terminal: oklch(0.2 0 0);
--terminal-foreground: oklch(1 0 0);
--terminal-hover: color-mix(in oklab, var(--terminal-foreground) 14%, var(--terminal));
--terminal-muted: color-mix(in oklab, var(--terminal-foreground) 8%, var(--terminal));
--card: oklch(0.3211 0 0);
--card-foreground: oklch(1 0 0);
--popover: oklch(0.3211 0 0);
--popover-foreground: oklch(1 0 0);
/* the primary hue drifts -4° toward dark, mirroring the reference */
--primary: oklch(0.7044 0.1872 calc(var(--brand-hue) - 4));
--primary-foreground: oklch(0 0 0);
--primary-text: var(--primary);
--secondary: oklch(0.9691 0.2005 109.6228);
--secondary-foreground: oklch(0 0 0);
--muted: oklch(0.2178 0 0);
--muted-foreground: oklch(0.8452 0 0);
--accent: oklch(0.6755 0.1765 252.2592);
--accent-foreground: oklch(0 0 0);
--destructive: oklch(1 0 0);
--destructive-foreground: oklch(0 0 0);
--border: oklch(1 0 0);
--input: oklch(1 0 0);
--ring: var(--primary);
--success: oklch(0.72 0.16 145);
--success-foreground: oklch(0 0 0);
--warning: oklch(0.78 0.17 85);
--warning-foreground: oklch(0 0 0);
--info: oklch(0.74 0.14 245);
--info-foreground: oklch(0 0 0);
--error: oklch(0.72 0.16 25);
--error-foreground: oklch(0 0 0);
--chart-1: var(--primary);
--chart-2: var(--success);
--chart-3: var(--info);
--chart-4: var(--warning);
--chart-5: var(--error);
--shadow-color: hsl(0 0% 100%);
/* shadow GEOMETRY rides the light baseline rung for rung (Owner ruling,
2026-09-01: sizes must not drift between themes — only the INK
inverts to white; the old 4px-everywhere small rungs were copy-paste
drift, not design) */
--shadow-2xs: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-xs: 2px 2px 0px 0px hsl(0 0% 100% / 0.5);
/* ink compensation (F-11, 2026-09-02): the second layer's alpha is
deliberately NOT mirrored (0.5 light / 1.0 dark) — the black ring
rides directly on the white offset over a black ground, where
half-alpha would read as a gray smear; geometry stays rung for
rung, only the ink density compensates */
--shadow-sm: 2px 2px 0px 0px hsl(0 0% 100% / 1), 1px 1px 0px 1px hsl(0 0% 0% / 1);
--shadow: 4px 4px 0px 0px hsl(0 0% 100% / 1);
--shadow-md: 4px 4px 0px 0px hsl(0 0% 100% / 1), 4px 2px 4px -1px hsl(0 0% 0% / 1);
/* --shadow-lg removed with the light block (F-10) */
/* press poses — same minus-1px law as the light block above */
--shadow-xs-press: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-sm-press: 1px 1px 0px 0px hsl(0 0% 100% / 1), 0px 0px 0px 1px hsl(0 0% 0% / 1);
--shadow-md-press: 3px 3px 0px 0px hsl(0 0% 100% / 1), 3px 1px 4px -1px hsl(0 0% 0% / 1);
/* elevation grammar, dark side: same geometry rung for rung, the
ink inverted to white (the white-shadow law); --shadow-paper is
theme-INDEPENDENT (paper stays white — see the light block).
The engrave duet inverts BOTH inks (the law's mechanical face —
the glow wall's black on dark reads as the carved sheen) */
--jx-engrave-shade: hsl(0 0% 100% / 0.4);
--jx-engrave-glow: hsl(0 0% 0% / 0.96);
--shadow-engrave: inset 1px 1px 0px 0px var(--jx-engrave-shade),
inset -1px -1px 0px 0px var(--jx-engrave-glow);
--shadow-well: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--shadow-well-hover: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.28);
/* floating-surface law, dark side: inverted — scrims and the shadow
layer are semi-transparent WHITE and BRIGHTEN (the white-shadow
law; same 0.32 veil strength as light mode's black) */
--scrim: hsl(0 0% 100% / 0.1);
--surface-shadow: oklch(0 0 0 / 0.32); /* black — r14-17, Owner */
/* ── the surface ladder, dark side (explicit-props §7 / task 1.1):
the M3 dark law — shadows are weak here, the STEPS carry the
hierarchy; the rungs LIGHTEN upward, away from the page void,
and stay below --card (0.3211 — the existing panel tokens keep
their place above the ladder). 减色墨律: role steps, never
overlays. This block feeds the generated prefers-color-scheme
projection in jx-pure.css (gen-jx-auto-dark — single source). */
--surface: var(--background);
--surface-container-lowest: oklch(0.115 0 0);
--surface-container-low: oklch(0.185 0 0);
--surface-container: oklch(0.205 0 0);
--surface-container-high: oklch(0.245 0 0);
--surface-container-highest: oklch(0.29 0 0);
--surface-concave: var(--background);
/* ── the elevation level table, dark side (explicit-props §0.1/§7 /
task 1.2): geometry pinned rung for rung with light (the
2026-09-01 law — sizes never drift between themes), the ink
inverted to white at reduced alpha — the soft-lens compensation
(dark hierarchy rides the LADDER; full-alpha white glow through
a 12px blur would wash it). level-1 keeps the inset duet's
single shade wall at the well-tier strength. */
--jx-elevation-level-1-shadow:
inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--jx-elevation-level-1-surface: var(--surface-concave);
--jx-elevation-level0-shadow: none;
--jx-elevation-level0-surface: var(--surface);
--jx-elevation-level1-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 1px 3px 1px hsl(0 0% 100% / 0.08);
--jx-elevation-level1-surface: var(--surface-container-lowest);
--jx-elevation-level2-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 2px 6px 2px hsl(0 0% 100% / 0.08);
--jx-elevation-level2-surface: var(--surface-container-low);
--jx-elevation-level3-shadow:
0px 1px 3px 0px hsl(0 0% 100% / 0.16),
0px 4px 8px 3px hsl(0 0% 100% / 0.08);
--jx-elevation-level3-surface: var(--surface-container);
--jx-elevation-level4-shadow:
0px 2px 3px 0px hsl(0 0% 100% / 0.16),
0px 6px 10px 4px hsl(0 0% 100% / 0.08);
--jx-elevation-level4-surface: var(--surface-container-high);
--jx-elevation-level5-shadow:
0px 4px 4px 0px hsl(0 0% 100% / 0.16),
0px 8px 12px 6px hsl(0 0% 100% / 0.08);
--jx-elevation-level5-surface: var(--surface-container-highest);
/* the color axis' effective carrier — dark's own --primary (the
hue-drifted one; re-declared per theme scope, the canvas-bug
law) */
--jx-color-effective: var(--primary);
color-scheme: dark;
}
/* the scope-root companion: without it B0's color-scheme: light would
out-shout the inherited root scheme and native pickers/scrollbars
would stay light under dark tokens (the inverted-A2 bug) */
:where(.jx-auto-dark) :where(.jx-pure):not(.jx-light, .jx-light *):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
}
/* ==== END GENERATED · jx-auto-dark ==== */
demo
Forms
The migrated native-form law, now element-scoped under a TYPE ALLOWLIST: text-like lanes take the bordered box; checkbox/radio/range/color are full pure-CSS repaints (native state, label and FormData keep working — appearance:none strips paint only). select is ALWAYS the jx chevron inside .jx-pure (gradient-drawn, single-select); number keeps its PLATFORM stepper (the only zero-JS stepper there is); time/date/month/week lanes carry the ink indicators. hidden/file are never touched. Layering (D3): Tier 1 keeps the platform controls by law — the registry Input component builds on these same classes and layers the custom ones on top (the −/+ number stepper, the embedded Calendar/month/time panels); its bare native-controls attribute opts back into the platform behavior shown here.
jx-pure · forms — the type allowlist
The migrated native-form law, element-scoped: text-like lanes take the bordered box; checkbox/radio/range/color are full pure-CSS repaints (native state, label and FormData keep working); select always carries the jx chevron inside the scope; number keeps its platform stepper. The no-jx-pure select island demonstrates the reverse scope.
/**
* jx-pure — the face of jixoai-ui (registry/files/theme/jx-pure.css).
*
* V3 (css-laws, 2026-08-28): the native form-control laws are
* SINGLE-SOURCED as typed TS objects in packages/css-laws/src/laws.
* THIS file carries two GENERATED projections of that source (the
* @apply chain is retired — TW4 dev did not reliably emit complex
* utilities onto element selectors):
* Part A slot — the Tier-2 opt-in classes (.jx-control, .jx-slider,
* …), unlayered by design (they beat layered utilities)
* Part B slot — the bare-element defaults under :where(.jx-pure),
* inside this sheet's @layer components
* Regenerate after editing laws: npx tsx packages/css-laws/src/build.ts
* Non-form-control face laws (typography, links, buttons, fieldset,
* details, lists, tables, progress, figure, validation matrix, scope
* law) remain face-authored below.
*
* A · opt-in classes = GENERATED alias slot (css-laws)
* B · element defaults = GENERATED face slot (css-laws) + face-authored laws
* C · degradation laws (face-owned transitions only)
* D · auto-dark (GENERATED by scripts/gen-jx-auto-dark.mjs)
*
* Scope law: .jx-pure is a subtree wrapper — it never reaches into
* shadow roots (CustomElements must @import this sheet inside their
* own shadow style). dialog/popover/tooltip are Tier-2 territory.
*/
/* =====================================================================
A · OPT-IN CLASSES — @apply applications of the standard layer
(the declarations live once in jixoai.css; these selectors only
bind them to the opt-in vocabulary)
===================================================================== */
/* opt-in classes = GENERATED applications of the standard layer
(the declarations live once in packages/css-laws/src/laws; these
selectors bind them to the opt-in vocabulary — Tier-2, unlayered
by design: they beat layered utilities) */
/* @jixoai/css-laws:begin:jx-html-alias — GENERATED, do not edit (source: packages/css-laws/src/laws) */
.jx-slider {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
.jx-slider::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider:dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
.jx-slider[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
.jx-slider:focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
.jx-slider:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-color-swatch {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
.jx-color-swatch::-webkit-color-swatch-wrapper {
padding: 0;
}
.jx-color-swatch::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
.jx-color-swatch::-moz-color-swatch {
border: 0;
border-radius: 0;
}
.jx-tgroup {
corner-shape: var(--corner-shape, bevel);
display: inline-flex;
width: fit-content;
flex-wrap: wrap;
overflow: hidden;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--card);
box-shadow: var(--shadow-2xs);
}
.jx-tgroup> label {
display: inline-flex;
align-items: center;
min-block-size: var(--jx-hit, 2.5rem);
padding-block: calc((var(--jx-hit, 2.5rem) - var(--jx-line, 1.25rem)) / 2);
padding-inline: var(--jx-inset, 0.75rem);
font-family: var(--font-nav);
font-size: var(--jx-text, 0.8125rem);
line-height: var(--jx-line, 1.25rem);
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted-foreground);
background-color: transparent;
border-inline-end: 1px solid var(--border);
cursor: pointer;
user-select: none;
transition: color 150ms ease-out, background-color 150ms ease-out;
}
.jx-tgroup> label:last-child {
border-inline-end: 0;
}
.jx-tgroup> label:not(:has(input:disabled)):hover {
color: var(--foreground);
}
.jx-tgroup> label:has(input:checked) {
background-color: var(--primary);
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:checked):not(:has(input:disabled)):hover {
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-tgroup> label:has(input:disabled) {
cursor: not-allowed;
opacity: 0.45;
}
.jx-tgroup> label > input {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.jx-tgroup[data-chrome='bare'] {
border: 0;
background: transparent;
box-shadow: none;
border-radius: 0;
overflow: visible;
}
.jx-tgroup[data-chrome='bare'] > label {
border-inline-end: 0;
flex: 1 1 auto;
justify-content: center;
}
.jx-tgroup[data-chrome='bare'] > label:not(:has(input:disabled)):hover {
color: var(--foreground);
background-color: color-mix(in oklab, var(--muted) 55%, transparent);
}
@media (prefers-reduced-motion: reduce) {
.jx-tgroup> label {
transition: none;
}
}
.jx-control {
box-sizing: border-box;
display: block;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding: var(--jx-gap, 0.5rem) var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font-size: var(--jx-text, 0.875rem);
color-scheme: light;
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control:focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
.jx-control:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-control[aria-invalid='true'] {
border-style: dashed;
border-color: var(--error);
color: var(--error);
}
.jx-control[aria-invalid='false'] {
border-color: var(--primary);
}
.jx-control::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control[type='email'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
.jx-control {
transition: none;
}
}
.jx-control-shell {
box-sizing: border-box;
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
font-size: var(--jx-text, 0.875rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
box-shadow: var(--shadow-well);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control-shell:has(> .jx-html-clear:last-child) {
padding-inline-end: 0;
}
.jx-control-shell:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control-shell:has(:focus) {
border-color: var(--ring);
}
.jx-control-shell:has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-control-shell:has([aria-invalid='true']), .jx-control-shell.jx-invalid {
border-style: dashed;
}
.jx-control-shell:has(:disabled) {
border-color: var(--muted);
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
.jx-control-shell {
transition: none;
}
}
.jx-control-lane {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
padding: 0;
outline: none;
background: transparent;
color: var(--foreground);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
}
.jx-control-lane::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control-lane::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control-lane[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control-lane[type='email'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
/* @jixoai/css-laws:end:jx-html-alias */
.jx-control-shell.jx-slotted {
padding-inline: var(--jx-inset, 0.75rem);
}
.jx-control-shell .jx-control-lane {
padding-inline: 0;
}
.jx-field {
display: flex;
flex-direction: column;
gap: var(--jx-stack, 0.5rem);
width: 100%;
min-width: 0;
}
.jx-label {
font-family: var(--font-nav);
/* secondary-text is a density ROLE (density-adoption §3): the label
* tracks the ambient scope instead of a fixed 11px (2026-08-29) */
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
cursor: pointer;
}
.jx-error {
display: flex;
align-items: center;
gap: 0.25rem;
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--destructive);
}
.jx-error-mark {
font-weight: bold;
}
/* the shell carries NO chrome itself (final-check ruling): the box
* chrome — border AND fill — lives on a ::before BAND whose height
* matches the -webkit-color-swatch-wrapper (the actual color chip's
* lane). 2026-08-29: the fill moved OFF the shell — an element-painted
* background leaks a full-height rectangle that ears out above/below
* the band on any surface where ambient ≠ --background (cards,
* panels, dark); the band now fills itself.
*
* GEOMETRY LAW (final-check ruling 2, the checkbox/range precedent):
* the chip is a LOCKED size-and-ratio block — height = the hit lane,
* aspect 7:4 (≈4.8rem at the 2.75rem hit — visually balanced, NOT a
* literal width), and the shell is its own SIZE CONTAINER: every
* internal geometry derives from 100cqh, so a density change (or a
* consumer height override) scales the whole chip proportionally —
* the swatch circle, the band, the pill radius, the glyph. The hit
* token sets ONLY the height; nothing else reads it. */
.jx-color-shell {
display: flex;
flex: none;
/* the shell's internal ladder (swatch z1, pipette ::after z2, the
custom-picker overlay z1) is COMPONENT-PRIVATE: container-type
does NOT establish a stacking context (measured, the isolation
clause 2026-09-09), so the shell roots it explicitly — the
deferred class-(a) tail cleared */
isolation: isolate;
/* fit-content protects the ratio-derived width from stretch (grid
tracks, block flow) while aspect-ratio + the locked height keep
it the chip's intrinsic 7:4 */
width: fit-content;
height: var(--jx-hit, 2.5rem);
aspect-ratio: 7 / 4;
container-type: size;
cursor: pointer;
position: relative;
transition: box-shadow 150ms ease-out;
}
.jx-color-shell::before {
content: '';
position: absolute;
inset-inline: 0;
inset-block: calc(100cqh / 6);
border: 1px solid var(--border);
background: var(--background);
pointer-events: none;
corner-left-shape: round;
/* band height = 100cqh − 2×(100cqh/6) = 100cqh × 2/3 — half of it
is the true-semicircle pill radius (no clamp hack) */
border-top-left-radius: calc(100cqh / 3);
border-bottom-left-radius: calc(100cqh / 3);
corner-right-shape: bevel;
/* the right radius rides the SAME cq quantum as the band inset
(100cqh/6 ≈ 8px at the default hit — was var(--radius, 8px),
which froze while every other edge scaled with the container;
B4: no internal dimension outside cq units) */
border-top-right-radius: calc(100cqh / 6);
border-bottom-right-radius: calc(100cqh / 6);
}
.jx-color-expand {
/* both dimensions definite → aspect-ratio yields; the chip keeps
its locked height across the full row.
FLEX PARTICIPATION is re-opened here on purpose: the base shell's
flex:none protects the COMPACT chip, but it also beats any layered
flex utility (this zone is unlayered) — so width:100% alone would
size against the WHOLE flex container and overflow any sibling
(the Tier-1 demo row, 2026-08-29: 77+12+329 > 329). grow reclaims
the full row, shrink shares it; block flow is untouched. */
width: 100%;
flex: 1 1 auto;
}
.jx-color-shell:has([aria-invalid='true'])::before,
.jx-color-shell.jx-invalid::before {
border-style: dashed;
}
.jx-color-shell .jx-color-swatch {
position: relative;
z-index: 1;
flex: none;
/* the chip lane = the container's full height; the swatch circle
inside sizes from the input's own padding (also cqh-relative) */
width: 100cqh;
height: auto;
align-self: stretch;
border: 0;
border-inline-end: 1px solid var(--border);
padding: calc(100cqh / 6);
}
.jx-color-shell .jx-color-swatch:focus-visible {
outline: none;
}
/* clear button: SUPERSEDED by jx-html-clear in the standard layer */
/* @jixoai/css-laws:begin:jx-icon-vocab — GENERATED, do not edit (source: packages/css-laws/src/icon-vocab) */
/* the pipette glyph — an ICON SLOT on the WRAPPER (input[type=color]
* is a replaced element whose ::after is unreliable across engines;
* the label wrapper is non-replaced and paints reliably) */
.jx-color-shell::after {
content: '';
position: absolute;
/* decorative carrier (the law's TRANSIENT INK family) + a ladder
rung — z2 orders against the swatch z1 INSIDE the shell, whose
own isolation: isolate roots the ladder (the isolation clause,
2026-09-09; the shell rule lives in the hand zone above) */
z-index: 2;
/* proportional optics: glyph ≈ 36% of the lane, end inset ≈ 27% —
scale with the container, not with font size */
inset-inline-end: calc(100cqh * 0.27);
top: 50%;
width: calc(100cqh * 0.36);
height: calc(100cqh * 0.36);
translate: 0 -50%;
color: var(--muted-foreground);
background-color: currentColor;
-webkit-mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
pointer-events: none;
}
.jx-color-shell:hover::after {
color: var(--foreground);
}
/* the color-picker chevron — an ICON SLOT (mask, currentColor themes) */
.jx-color-picker-chevron {
display: block;
width: 0.75rem;
height: 0.75rem;
background-color: currentColor;
-webkit-mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
}
/* =====================================================================
Icon vocabulary — the mask/currentColor law. One alpha-only URI per
glyph; the encoded stroke %23000 is an ALPHA SOURCE ONLY. The INK
variants (calendar/clock/valid/invalid) serve UA-shadow pseudos that
reject author mask paint; .dark flips them to %23fff, .jx-light back.
===================================================================== */
@layer theme {
:root {
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* THEME-SCOPED placeholder (canvas bug, Owner 2026-09-04 — same law
as the variant-grammar slots in jixoai.css): custom properties
substitute their var() at the DECLARING element — a :root-only
--jx-placeholder handed every descendant the root's
already-substituted mix, so a scoped .dark/.jx-light
(component-canvas stage, terminal-card, print) flipping
--foreground/--background never re-flipped the placeholder ink
with it. The selector list re-declares the slot ON each theme
scope: one declaration point, zero duplicates */
:root,
.jx-light,
.dark {
--jx-placeholder: color-mix(in oklab, var(--foreground) 40%, var(--background));
}
}
.dark {
/* the author-painted icon set flips to white ink in dark (the
-ink quartet's law extended to the plain slots the input/select
laws consume — black alpha URIs vanish on the dark token sheet) */
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
.jx-light {
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* @jixoai/css-laws:end:jx-icon-vocab */
/* =====================================================================
The zero-class STRUCTURAL input group: a label wrapping a text-like
control AND at least one span composes into the shell — the label
takes the box law, the spans ride as prefix/suffix cells, the
control goes chromeless. NO opt-in class needed.
===================================================================== */
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) {
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
padding-inline: var(--jx-inset, 0.75rem);
cursor: text;
transition: box-shadow 150ms ease-out;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):hover {
box-shadow: var(--shadow-2xs);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > span {
display: inline-flex;
align-items: center;
flex: none;
font-size: var(--jx-text, 0.875rem);
color: var(--muted-foreground);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > input {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
outline: none;
background: transparent;
color: var(--foreground);
font: inherit;
font-size: var(--jx-text, 0.875rem);
padding-inline: 0;
}
/* =====================================================================
Switch size modifiers (face-owned; the standard utility carries the
density-alias default, these opt into explicit sizes)
===================================================================== */
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-sm:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-sm input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 2rem;
--jx-toggle-track: 1.25rem;
--jx-toggle-knob: 0.75rem;
}
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-lg:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-lg input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 3rem;
--jx-toggle-track: 1.5rem;
--jx-toggle-knob: 1.25rem;
}
/* =====================================================================
Bare color input: the locked square standalone (without a .jx-color-
shell wrapper)
===================================================================== */
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: calc(var(--jx-hit, 2.5rem) - 2px);
padding: 2px;
}
/* =====================================================================
Reduced-motion law: the sheet's face-owned transitions neutralize.
===================================================================== */
@media (prefers-reduced-motion: reduce) {
.jx-control,
.jx-control-shell,
.jx-color-shell {
transition: none;
}
}
/* =====================================================================
B · ELEMENT DEFAULTS — the .jx-pure subtree face.
Every rule rides :where(.jx-pure) so the scope class contributes
ZERO specificity inside @layer components: Tailwind utilities
(utilities layer) and any unlayered author css override these
cheaply, and non-Tailwind static consumers override with plain
css. Colors come from tokens or currentColor ONLY — no hardcoded
paint survives a theme flip.
===================================================================== */
@layer components {
/* ---- B0 · the scope root: color-scheme follows the theme classes
the token sheet owns. color-scheme INHERITS — one declaration
themes every native picker, scrollbar and form control in the
subtree: light under :root, dark under .dark (ancestor or self),
forced light under .jx-light. */
:where(.jx-pure):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
/* density adoption (native-contract-fusion Phase 5): the scope
root rides the density interface's text/leading aliases (the
typography LADDER above keeps its fixed steps — declared gap) */
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.6);
}
:where(.dark) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.dark):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
:where(.jx-light) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.jx-light):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
}
/* =====================================================================
B1 · Typography — documented rem steps (the repo ships no
typography size tokens; these literals ARE the scale until a
token ruling lands — do not scatter new sizes elsewhere). The
flow margins are EXPLICIT because preflight zeroes them: a
Tailwind host without this block would render wall-of-text prose.
===================================================================== */
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6):not(.no-jx-pure, .no-jx-pure *) {
margin: 1.5em 0 0.6em;
font-weight: 700;
line-height: 1.25;
color: var(--foreground);
}
:where(.jx-pure) h1:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.875rem;
}
:where(.jx-pure) h2:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.5rem;
}
:where(.jx-pure) h3:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.25rem;
}
:where(.jx-pure) h4:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.125rem;
}
:where(.jx-pure) :where(h5, h6):not(.no-jx-pure, .no-jx-pure *) {
font-size: 1rem;
}
:where(.jx-pure) :where(p, ul, ol, dl, blockquote, pre, table, hr):not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
}
:where(.jx-pure) p:not(.no-jx-pure, .no-jx-pure *) {
line-height: 1.6;
}
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6) :where(p, ul, ol, dl, blockquote, pre, table):first-child:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0;
}
:where(.jx-pure) small:not(.no-jx-pure, .no-jx-pure *) {
font-size: 0.8125rem;
color: var(--muted-foreground);
}
:where(.jx-pure) :where(strong, b):not(.no-jx-pure, .no-jx-pure *) {
font-weight: 700;
}
:where(.jx-pure) blockquote:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-start: 0.875rem;
border-inline-start: 1px solid var(--border);
color: var(--muted-foreground);
}
:where(.jx-pure) :where(code, kbd, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.1em 0.4em;
border: 1px solid var(--border);
background: var(--muted);
font-family: var(--font-mono);
font-size: 0.8125rem;
}
:where(.jx-pure) kbd:not(.no-jx-pure, .no-jx-pure *) {
/* the key cap is ENGRAVED, not lifted (F-2, adversarial-review
2026-09-02 — Owner kbd ruling): --shadow-engrave inset, the
elevation grammar's engrave tier, unified with the registry kbd
component (shadow-engrave). The old `0 1px 0 var(--border)`
lifted-edge dialect is retired — one kbd face across the bare
element and the component. */
box-shadow: var(--shadow-engrave);
}
:where(.jx-pure) pre:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.75rem 1rem;
border: 1px solid var(--border);
background: var(--background);
overflow: auto;
font-family: var(--font-mono);
font-size: 0.8125rem;
line-height: 1.55;
}
/* the code-in-pre lane drops its inline box — the pre owns the box */
:where(.jx-pure) pre :where(code, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0;
border: 0;
background: transparent;
font-size: inherit;
}
:where(.jx-pure) mark:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.05em 0.25em;
background: color-mix(in oklab, var(--secondary) 45%, var(--background));
color: var(--foreground);
}
:where(.jx-pure) hr:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 1.5rem;
border: 0;
border-top: 1px solid var(--border);
}
/* =====================================================================
B2 · Links — the site link law (press-button link variant):
primary text, no underline at rest, underline on hover. Nav links
read as chrome, not prose: foreground at rest, primary + underline
as the hover cue.
===================================================================== */
:where(.jx-pure) a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-underline-offset: 4px;
}
:where(.jx-pure) a:hover:not(.no-jx-pure, .no-jx-pure *) {
text-decoration-line: underline;
}
:where(.jx-pure) nav a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--foreground);
}
:where(.jx-pure) nav a:hover:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-decoration-line: underline;
}
/* =====================================================================
B3 · Buttons — the .jx-press physics restated element-scoped
(hover grows the token shadow + bg-muted; active presses +1px
into the page with the *-press twin — same variable contract,
no WAAPI, no second geometry law). .jx-button is the EXPLICIT
channel for link-look buttons (Codex D2: never auto-style
a[role=button] — CSS cannot add command semantics). Focus is
deliberately NOT set here: the host's focus law owns it (site
base layer paints a/button; static pages keep the UA ring).
===================================================================== */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *) {
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.375rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 1rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
line-height: 1.45;
text-decoration: none;
cursor: pointer;
box-shadow: var(--jx-press-shadow, var(--shadow-xs));
transition:
translate 150ms ease-out,
box-shadow 150ms ease-out,
background-color 150ms ease-out,
border-color 150ms ease-out,
color 150ms ease-out;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):hover:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
box-shadow: var(--jx-press-shadow-hover, var(--shadow-sm));
}
/* :active LAST — at equal specificity the later rule wins the hover pose */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: 1px 1px;
box-shadow: var(--jx-press-shadow-active, var(--shadow-sm-press));
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
cursor: not-allowed;
box-shadow: none;
}
/* =====================================================================
B4+B5 · form controls = @apply applications of the standard
layer (the 13-type allowlist rides each selector; the number lane
keeps the PLATFORM stepper by sharing jx-html-input; checkbox
excludes [role=switch] so the switch gets its own utility) ----- */
/* GENERATED between the markers (css-laws V3): the bare-element
defaults — same declaration source as the .jx-html-* classes,
serialized as element-default rules under :where(.jx-pure) */
/* @jixoai/css-laws:begin:jx-html-face — GENERATED, do not edit (source: packages/css-laws/src/laws) */
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-textarea-min, 5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
height: auto;
resize: vertical;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
--jx-icon-chevron-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
cursor: pointer;
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):disabled, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
@supports not selector(::-moz-range-progress) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
background-image: var(--jx-icon-chevron, var(--jx-icon-chevron-svg));
background-position: right var(--jx-inset, 0.75rem) center;
background-size: var(--jx-icon, 1.25rem);
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
filter: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]) {
min-height: 5.75rem;
padding-block: 0.375rem 0.5rem;
cursor: default;
background-image: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
cursor: pointer;
transition: background-color 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate::before {
opacity: 1;
transform: rotate(0deg);
clip-path: polygon(10% 40%, 10% 60%, 45% 60%, 55% 60%, 90% 60%, 90% 40%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked, :where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate {
background: var(--primary);
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 50%;
background: var(--background);
cursor: pointer;
transition: border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
content: none;
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::after {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
border-radius: 50%;
background: var(--primary);
transform: scale(0);
transition: transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::after {
transform: scale(1);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--background);
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
position: relative;
width: var(--jx-toggle-width, 2.5rem);
height: var(--jx-toggle-track, 1.5rem);
margin: 0;
flex: none;
padding: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
border: 0;
box-shadow: 0 0 0 1px var(--border) inset;
border-radius: calc(infinity * 1px);
background: var(--muted);
cursor: pointer;
transition: background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
inset-block: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inset-inline-start: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inline-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
block-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
border-radius: calc(infinity * 1px);
border: var(--jx-toggle-knob-border, 1px) solid var(--jx-toggle-knob-border-color, var(--primary));
background: var(--background);
transform: translateX(0);
transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1), background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), border-color 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
transform: translateX(calc(var(--jx-toggle-width, 2.5rem) - var(--jx-toggle-track, 1.5rem)));
background: var(--primary-foreground);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
box-shadow: 0 0 0 1px var(--primary) inset;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)) {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch-wrapper {
padding: 0;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-moz-color-swatch {
border: 0;
border-radius: 0;
}
/* @jixoai/css-laws:end:jx-html-face */
/* ---- B6 · label / fieldset / legend (face-owned; not form-
control law — the one-opacity-owner disabled law) -------------
===================================================================== */
:where(.jx-pure) label:not(.no-jx-pure, .no-jx-pure *) {
cursor: pointer;
}
:where(.jx-pure) fieldset:not(.no-jx-pure, .no-jx-pure *) {
min-width: 0;
margin-block: 0.75rem;
padding: 0.875rem 1rem 1rem;
border: 1px solid var(--border);
border-radius: 0;
}
:where(.jx-pure) fieldset:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* ONE opacity owner per subtree (Codex review A3): the group dims to
.5 and the controls inside stay at 1 — two stacked .5 layers
composite to ~.25 and the contrast collapses */
:where(.jx-pure) fieldset:disabled :where(input, textarea, select, button):not(.no-jx-pure, .no-jx-pure *) {
opacity: 1;
cursor: not-allowed;
}
:where(.jx-pure) legend:not(.no-jx-pure, .no-jx-pure *) {
padding-inline: 0.5rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* =====================================================================
B7 · details / summary — document-flow disclosure ONLY (dialog /
popover / tooltip stay Tier-2, Codex D3). Static marker swap, no
open/close animation (progressive enhancement deferred); the
visible focus ring is never replaced by the marker.
===================================================================== */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *) {
display: flex;
align-items: center;
gap: 0.625rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
font-size: 0.875rem;
list-style: none;
cursor: pointer;
transition:
border-color 150ms ease-out,
box-shadow 150ms ease-out;
}
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::-webkit-details-marker {
display: none;
}
/* the marker: a bordered square holding + / − (static swap) */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '+';
box-sizing: border-box;
display: grid;
place-items: center;
width: 1.125rem;
height: 1.125rem;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--muted-foreground);
font-family: var(--font-nav);
font-size: 12px;
line-height: 1;
}
:where(.jx-pure) details[open] > summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '−';
}
:where(.jx-pure) summary:hover:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--primary); /* leans like the checkbox border */
}
:where(.jx-pure) summary:focus-visible:not(.no-jx-pure, .no-jx-pure *) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) details > * + *:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.5rem;
}
/* =====================================================================
B8 · lists / dl — restore the document-flow markers preflight
removes (classless parity) and theme them; nav's link law lives
in B2.
===================================================================== */
:where(.jx-pure) ul:not(.no-jx-pure, .no-jx-pure *) {
list-style: disc;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) ol:not(.no-jx-pure, .no-jx-pure *) {
list-style: decimal;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) li:not(.no-jx-pure, .no-jx-pure *)::marker {
color: var(--muted-foreground);
}
:where(.jx-pure) dl:not(.no-jx-pure, .no-jx-pure *) {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.375rem 1rem;
}
:where(.jx-pure) dt:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
:where(.jx-pure) dd:not(.no-jx-pure, .no-jx-pure *) {
margin: 0;
}
/* =====================================================================
B9 · Tables — the bordered grid law.
===================================================================== */
:where(.jx-pure) table:not(.no-jx-pure, .no-jx-pure *) {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
:where(.jx-pure) caption:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.375rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
caption-side: bottom;
text-align: start;
}
:where(.jx-pure) :where(th, td):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
text-align: start;
}
:where(.jx-pure) th:not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
font-family: var(--font-nav);
font-size: 11px;
font-weight: 400;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
white-space: nowrap;
}
:where(.jx-pure) tbody tr:hover:not(.no-jx-pure, .no-jx-pure *) {
background: color-mix(in oklab, var(--muted) 26%, transparent);
}
/* =====================================================================
B10 · progress / meter / output (Owner completion round, 2026-08-24:
the Codex D6 deferral is overruled — the contracts exist now).
progress: the range-track geometry (8px bordered box, primary
fill); indeterminate trades the fill for a sliding stripe, fully
static under reduced motion. meter: the same box with the
SEMANTIC token mapping — optimum=primary, suboptimal=secondary,
even-less-good=destructive (no hardcoded traffic lights). output:
the mono result lane. Engine pseudos live in SEPARATE rules (the
R1 law: a shared -moz list is dropped whole by Chromium).
===================================================================== */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *) {
display: block;
box-sizing: border-box;
width: 100%;
height: 0.5rem; /* the 8px track family (incl. borders) */
margin: 0;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
appearance: none;
-webkit-appearance: none;
overflow: hidden;
}
:where(.jx-pure) progress:disabled:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* chromium: the track pseudo + the value pseudo */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-bar {
background: var(--background);
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-value {
background: var(--primary);
transition: width 150ms ease-out;
}
/* indeterminate: no percent exists — a muted stripe slides across.
The stripe rides the ELEMENT's own background, never the UA
pseudos: engines reject author paint/animation on progress
pseudos exactly like the number spinners (Codex r4 R4-1 — the
pseudo path compiled but never animated). Part C parks it under
reduced motion. */
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *) {
background:
linear-gradient(in oklab, var(--muted), var(--muted)) 0 0 / 40% 100% no-repeat,
var(--background);
animation: jx-progress-slide 1.2s linear infinite;
}
/* firefox: the element is the track; the bar pseudo is the value */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: var(--primary);
}
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: transparent; /* the element's stripe owns the paint */
}
/* meter: the semantic three-state fill (token-mapped, monochrome law) */
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-bar {
background: var(--background);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-optimum-value {
background: var(--primary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-suboptimum-value {
background: var(--secondary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-even-less-good-value {
background: var(--destructive);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--primary);
}
:where(.jx-pure) meter:-moz-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--secondary);
}
:where(.jx-pure) meter:-moz-sub-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--destructive);
}
/* the stripe keyframes live OUTSIDE the layer's rule bodies… they
are defined once here (keyframes are global; the jx- prefix keeps
the namespace) — declared at the layer's end so both engine rules
above can reference them */
}
@keyframes jx-progress-slide {
from {
background-position: -40% 0, 0 0;
}
to {
background-position: 140% 0, 0 0;
}
}
@layer components {
/* output: the calculation result lane — mono, foreground, inline */
:where(.jx-pure) output:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-mono);
font-size: 0.875rem;
color: var(--foreground);
}
/* =====================================================================
B11 · figure / media — the documentation flow. figure carries the
flow margin + the bordered plate; figcaption rides the caption
law (nav font, small caps, muted, below). Media never overflows
its lane.
===================================================================== */
:where(.jx-pure) :where(img, video):not(.no-jx-pure, .no-jx-pure *) {
max-width: 100%;
height: auto;
}
:where(.jx-pure) figure:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.375rem;
max-width: 100%;
}
:where(.jx-pure) figure > :where(img, video, svg, pre, table):not(.no-jx-pure, .no-jx-pure *) {
border: 1px solid var(--border);
}
:where(.jx-pure) figcaption:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* ---- B13 · switch = @apply application (the ONE input law;
[role=switch] discriminates it from the checkbox) ------------- */
/* the label posture: a wrapping label dims with its input */
:where(.jx-pure) label:has(> input[type='checkbox'][role='switch']):not(.no-jx-pure, .no-jx-pure *) {
display: inline-flex;
align-items: center;
gap: var(--jx-gap, 0.5rem);
cursor: pointer;
user-select: none;
min-block-size: var(--jx-hit, 2.5rem);
&:has(input:disabled) {
cursor: not-allowed;
opacity: 0.5;
}
}
/* =====================================================================
B14 · validation states — the Pico state matrix on the SEMANTIC
palette (openspec D5): aria-invalid='false' leans --success ('✓'
ink + success border + success hover lean); aria-invalid='true'
flips every accent to --error (dashed lanes + '!' ink, checked
fills, the radio DOT, switch track, range fill + thumb).
--destructive is NOT used here — it stays the monochrome
inversion pair for destructive actions. Native :invalid stays
deliberately unhooked (no empty-required surprises).
===================================================================== */
/* lanes: border-color states + the ink glyphs */
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
background-image: var(--jx-icon-invalid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: 2rem;
background-image: var(--jx-icon-valid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
/* checkbox / radio: the checked accent flips to error */
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:indeterminate:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::after {
background: var(--error-foreground);
}
:where(.jx-pure) input[type='checkbox'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success); /* the valid lean */
}
/* switch: the checked track flips */
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::before {
border-color: transparent;
}
/* range: fill + thumb flip */
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
--jx-slider-fill-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-webkit-slider-thumb {
border-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-moz-range-thumb {
background: var(--error);
}
}
/* =====================================================================
B12 · the reverse scope — .no-jx-pure (Owner third revision,
2026-08-24): the r8/r9 `all: revert !important` hatch was too
violent — it also rolled back the HOST's own utilities and inline
styles. Every face rule now carries the exclusion on its subject:
:not(.no-jx-pure, .no-jx-pure *) — an element that IS, or lives
inside, a no-jx-pure subtree never receives the face; everything
the host authored there is untouched. Part A opt-in classes still
work inside islands (author intent, not face paint). INHERITED
properties (color-scheme, custom property tokens) keep flowing
through islands from ancestors — the exclusion is element-level
paint, never a war against the page's theme or the host.
=====================================================================
*/
/* =====================================================================
C · DEGRADATION LAWS — motion and forced colors.
===================================================================== */
/* Reduced motion: FULL STILLNESS, not zero-duration animation (Codex
review B): every Part B transition goes none AND the interactive
displacements (the press translate, the thumb press transform) are
pinned back to their rest poses so nothing ever moves. */
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) :where(textarea, select):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
/* engine pseudos NEVER share a selector list — a non-forgiving list
with an unknown -moz pseudo is dropped WHOLE by Chromium (Codex
r2 R1); one rule per engine surface */
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
/* the indeterminate stripe parks: element animation off (the
authored -moz pseudo animation is likewise killed — one rule per
surface, and the -moz one stands alone) */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *) {
animation: none;
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
animation: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
:where(.jx-pure) input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
transition: none;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: none;
}
}
/* Forced colors (Windows High Contrast & friends): the custom-painted
controls revert to appearance:auto so the SYSTEM palette and glyphs
speak — author paint would flatten into the forced canvas and lose
the checked/unchecked distinction entirely. Box laws (borders,
outlines) survive: forced-colors keeps author borders as system
colors. The opt-in select ALSO drops its gradient chevron or the
restored platform arrow would double up with the leftover paint. */
@media (forced-colors: active) {
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='range']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='color']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select:not(.no-jx-pure, .no-jx-pure *) {
appearance: auto;
-webkit-appearance: auto;
background-image: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before,
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
content: none;
}
}
/* ==== BEGIN GENERATED · jx-auto-dark — scripts/gen-jx-auto-dark.mjs (do not hand-edit) ==== */
/* Derived 1:1 from jixoai.css's .dark block (single source). The gate
rides :where() so the whole variant stays maximally overridable; it
never fires where an explicit .dark already owns the theme, nor
inside .jx-light islands. Mount: <html class="jx-pure jx-auto-dark"> */
@media (prefers-color-scheme: dark) {
:where(.jx-auto-dark):not(.dark, .jx-light *) {
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--terminal: oklch(0.2 0 0);
--terminal-foreground: oklch(1 0 0);
--terminal-hover: color-mix(in oklab, var(--terminal-foreground) 14%, var(--terminal));
--terminal-muted: color-mix(in oklab, var(--terminal-foreground) 8%, var(--terminal));
--card: oklch(0.3211 0 0);
--card-foreground: oklch(1 0 0);
--popover: oklch(0.3211 0 0);
--popover-foreground: oklch(1 0 0);
/* the primary hue drifts -4° toward dark, mirroring the reference */
--primary: oklch(0.7044 0.1872 calc(var(--brand-hue) - 4));
--primary-foreground: oklch(0 0 0);
--primary-text: var(--primary);
--secondary: oklch(0.9691 0.2005 109.6228);
--secondary-foreground: oklch(0 0 0);
--muted: oklch(0.2178 0 0);
--muted-foreground: oklch(0.8452 0 0);
--accent: oklch(0.6755 0.1765 252.2592);
--accent-foreground: oklch(0 0 0);
--destructive: oklch(1 0 0);
--destructive-foreground: oklch(0 0 0);
--border: oklch(1 0 0);
--input: oklch(1 0 0);
--ring: var(--primary);
--success: oklch(0.72 0.16 145);
--success-foreground: oklch(0 0 0);
--warning: oklch(0.78 0.17 85);
--warning-foreground: oklch(0 0 0);
--info: oklch(0.74 0.14 245);
--info-foreground: oklch(0 0 0);
--error: oklch(0.72 0.16 25);
--error-foreground: oklch(0 0 0);
--chart-1: var(--primary);
--chart-2: var(--success);
--chart-3: var(--info);
--chart-4: var(--warning);
--chart-5: var(--error);
--shadow-color: hsl(0 0% 100%);
/* shadow GEOMETRY rides the light baseline rung for rung (Owner ruling,
2026-09-01: sizes must not drift between themes — only the INK
inverts to white; the old 4px-everywhere small rungs were copy-paste
drift, not design) */
--shadow-2xs: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-xs: 2px 2px 0px 0px hsl(0 0% 100% / 0.5);
/* ink compensation (F-11, 2026-09-02): the second layer's alpha is
deliberately NOT mirrored (0.5 light / 1.0 dark) — the black ring
rides directly on the white offset over a black ground, where
half-alpha would read as a gray smear; geometry stays rung for
rung, only the ink density compensates */
--shadow-sm: 2px 2px 0px 0px hsl(0 0% 100% / 1), 1px 1px 0px 1px hsl(0 0% 0% / 1);
--shadow: 4px 4px 0px 0px hsl(0 0% 100% / 1);
--shadow-md: 4px 4px 0px 0px hsl(0 0% 100% / 1), 4px 2px 4px -1px hsl(0 0% 0% / 1);
/* --shadow-lg removed with the light block (F-10) */
/* press poses — same minus-1px law as the light block above */
--shadow-xs-press: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-sm-press: 1px 1px 0px 0px hsl(0 0% 100% / 1), 0px 0px 0px 1px hsl(0 0% 0% / 1);
--shadow-md-press: 3px 3px 0px 0px hsl(0 0% 100% / 1), 3px 1px 4px -1px hsl(0 0% 0% / 1);
/* elevation grammar, dark side: same geometry rung for rung, the
ink inverted to white (the white-shadow law); --shadow-paper is
theme-INDEPENDENT (paper stays white — see the light block).
The engrave duet inverts BOTH inks (the law's mechanical face —
the glow wall's black on dark reads as the carved sheen) */
--jx-engrave-shade: hsl(0 0% 100% / 0.4);
--jx-engrave-glow: hsl(0 0% 0% / 0.96);
--shadow-engrave: inset 1px 1px 0px 0px var(--jx-engrave-shade),
inset -1px -1px 0px 0px var(--jx-engrave-glow);
--shadow-well: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--shadow-well-hover: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.28);
/* floating-surface law, dark side: inverted — scrims and the shadow
layer are semi-transparent WHITE and BRIGHTEN (the white-shadow
law; same 0.32 veil strength as light mode's black) */
--scrim: hsl(0 0% 100% / 0.1);
--surface-shadow: oklch(0 0 0 / 0.32); /* black — r14-17, Owner */
/* ── the surface ladder, dark side (explicit-props §7 / task 1.1):
the M3 dark law — shadows are weak here, the STEPS carry the
hierarchy; the rungs LIGHTEN upward, away from the page void,
and stay below --card (0.3211 — the existing panel tokens keep
their place above the ladder). 减色墨律: role steps, never
overlays. This block feeds the generated prefers-color-scheme
projection in jx-pure.css (gen-jx-auto-dark — single source). */
--surface: var(--background);
--surface-container-lowest: oklch(0.115 0 0);
--surface-container-low: oklch(0.185 0 0);
--surface-container: oklch(0.205 0 0);
--surface-container-high: oklch(0.245 0 0);
--surface-container-highest: oklch(0.29 0 0);
--surface-concave: var(--background);
/* ── the elevation level table, dark side (explicit-props §0.1/§7 /
task 1.2): geometry pinned rung for rung with light (the
2026-09-01 law — sizes never drift between themes), the ink
inverted to white at reduced alpha — the soft-lens compensation
(dark hierarchy rides the LADDER; full-alpha white glow through
a 12px blur would wash it). level-1 keeps the inset duet's
single shade wall at the well-tier strength. */
--jx-elevation-level-1-shadow:
inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--jx-elevation-level-1-surface: var(--surface-concave);
--jx-elevation-level0-shadow: none;
--jx-elevation-level0-surface: var(--surface);
--jx-elevation-level1-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 1px 3px 1px hsl(0 0% 100% / 0.08);
--jx-elevation-level1-surface: var(--surface-container-lowest);
--jx-elevation-level2-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 2px 6px 2px hsl(0 0% 100% / 0.08);
--jx-elevation-level2-surface: var(--surface-container-low);
--jx-elevation-level3-shadow:
0px 1px 3px 0px hsl(0 0% 100% / 0.16),
0px 4px 8px 3px hsl(0 0% 100% / 0.08);
--jx-elevation-level3-surface: var(--surface-container);
--jx-elevation-level4-shadow:
0px 2px 3px 0px hsl(0 0% 100% / 0.16),
0px 6px 10px 4px hsl(0 0% 100% / 0.08);
--jx-elevation-level4-surface: var(--surface-container-high);
--jx-elevation-level5-shadow:
0px 4px 4px 0px hsl(0 0% 100% / 0.16),
0px 8px 12px 6px hsl(0 0% 100% / 0.08);
--jx-elevation-level5-surface: var(--surface-container-highest);
/* the color axis' effective carrier — dark's own --primary (the
hue-drifted one; re-declared per theme scope, the canvas-bug
law) */
--jx-color-effective: var(--primary);
color-scheme: dark;
}
/* the scope-root companion: without it B0's color-scheme: light would
out-shout the inherited root scheme and native pickers/scrollbars
would stay light under dark tokens (the inverted-A2 bug) */
:where(.jx-auto-dark) :where(.jx-pure):not(.jx-light, .jx-light *):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
}
/* ==== END GENERATED · jx-auto-dark ==== */
demo
details / summary
Document-flow disclosure only — dialog, popover and tooltip surfaces stay Tier-2 (their top-layer + closing-order laws are component territory). The summary row carries a bordered square marker that statically swaps + ↔ −; the visible focus ring is never replaced by the marker; no open/close animation ships (progressive enhancement, reduced-motion safe by construction).
jx-pure · details / summary
Document-flow disclosure only — the summary row carries the bordered square marker that statically swaps + ↔ −; the visible focus ring is never replaced by the marker.
What is included in v1?
Typography, links, buttons, the form lanes, disclosure, lists, and tables — everything on this page.
And what is deliberately not?
Floating surfaces (dialog / popover / tooltip — Tier-2 territory) and select popup internals. The platform keeps those: their top-layer and closing-order laws are component ground.
/**
* jx-pure — the face of jixoai-ui (registry/files/theme/jx-pure.css).
*
* V3 (css-laws, 2026-08-28): the native form-control laws are
* SINGLE-SOURCED as typed TS objects in packages/css-laws/src/laws.
* THIS file carries two GENERATED projections of that source (the
* @apply chain is retired — TW4 dev did not reliably emit complex
* utilities onto element selectors):
* Part A slot — the Tier-2 opt-in classes (.jx-control, .jx-slider,
* …), unlayered by design (they beat layered utilities)
* Part B slot — the bare-element defaults under :where(.jx-pure),
* inside this sheet's @layer components
* Regenerate after editing laws: npx tsx packages/css-laws/src/build.ts
* Non-form-control face laws (typography, links, buttons, fieldset,
* details, lists, tables, progress, figure, validation matrix, scope
* law) remain face-authored below.
*
* A · opt-in classes = GENERATED alias slot (css-laws)
* B · element defaults = GENERATED face slot (css-laws) + face-authored laws
* C · degradation laws (face-owned transitions only)
* D · auto-dark (GENERATED by scripts/gen-jx-auto-dark.mjs)
*
* Scope law: .jx-pure is a subtree wrapper — it never reaches into
* shadow roots (CustomElements must @import this sheet inside their
* own shadow style). dialog/popover/tooltip are Tier-2 territory.
*/
/* =====================================================================
A · OPT-IN CLASSES — @apply applications of the standard layer
(the declarations live once in jixoai.css; these selectors only
bind them to the opt-in vocabulary)
===================================================================== */
/* opt-in classes = GENERATED applications of the standard layer
(the declarations live once in packages/css-laws/src/laws; these
selectors bind them to the opt-in vocabulary — Tier-2, unlayered
by design: they beat layered utilities) */
/* @jixoai/css-laws:begin:jx-html-alias — GENERATED, do not edit (source: packages/css-laws/src/laws) */
.jx-slider {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
.jx-slider::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider:dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
.jx-slider[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
.jx-slider:focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
.jx-slider:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-color-swatch {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
.jx-color-swatch::-webkit-color-swatch-wrapper {
padding: 0;
}
.jx-color-swatch::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
.jx-color-swatch::-moz-color-swatch {
border: 0;
border-radius: 0;
}
.jx-tgroup {
corner-shape: var(--corner-shape, bevel);
display: inline-flex;
width: fit-content;
flex-wrap: wrap;
overflow: hidden;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--card);
box-shadow: var(--shadow-2xs);
}
.jx-tgroup> label {
display: inline-flex;
align-items: center;
min-block-size: var(--jx-hit, 2.5rem);
padding-block: calc((var(--jx-hit, 2.5rem) - var(--jx-line, 1.25rem)) / 2);
padding-inline: var(--jx-inset, 0.75rem);
font-family: var(--font-nav);
font-size: var(--jx-text, 0.8125rem);
line-height: var(--jx-line, 1.25rem);
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted-foreground);
background-color: transparent;
border-inline-end: 1px solid var(--border);
cursor: pointer;
user-select: none;
transition: color 150ms ease-out, background-color 150ms ease-out;
}
.jx-tgroup> label:last-child {
border-inline-end: 0;
}
.jx-tgroup> label:not(:has(input:disabled)):hover {
color: var(--foreground);
}
.jx-tgroup> label:has(input:checked) {
background-color: var(--primary);
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:checked):not(:has(input:disabled)):hover {
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-tgroup> label:has(input:disabled) {
cursor: not-allowed;
opacity: 0.45;
}
.jx-tgroup> label > input {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.jx-tgroup[data-chrome='bare'] {
border: 0;
background: transparent;
box-shadow: none;
border-radius: 0;
overflow: visible;
}
.jx-tgroup[data-chrome='bare'] > label {
border-inline-end: 0;
flex: 1 1 auto;
justify-content: center;
}
.jx-tgroup[data-chrome='bare'] > label:not(:has(input:disabled)):hover {
color: var(--foreground);
background-color: color-mix(in oklab, var(--muted) 55%, transparent);
}
@media (prefers-reduced-motion: reduce) {
.jx-tgroup> label {
transition: none;
}
}
.jx-control {
box-sizing: border-box;
display: block;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding: var(--jx-gap, 0.5rem) var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font-size: var(--jx-text, 0.875rem);
color-scheme: light;
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control:focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
.jx-control:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-control[aria-invalid='true'] {
border-style: dashed;
border-color: var(--error);
color: var(--error);
}
.jx-control[aria-invalid='false'] {
border-color: var(--primary);
}
.jx-control::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control[type='email'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
.jx-control {
transition: none;
}
}
.jx-control-shell {
box-sizing: border-box;
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
font-size: var(--jx-text, 0.875rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
box-shadow: var(--shadow-well);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control-shell:has(> .jx-html-clear:last-child) {
padding-inline-end: 0;
}
.jx-control-shell:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control-shell:has(:focus) {
border-color: var(--ring);
}
.jx-control-shell:has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-control-shell:has([aria-invalid='true']), .jx-control-shell.jx-invalid {
border-style: dashed;
}
.jx-control-shell:has(:disabled) {
border-color: var(--muted);
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
.jx-control-shell {
transition: none;
}
}
.jx-control-lane {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
padding: 0;
outline: none;
background: transparent;
color: var(--foreground);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
}
.jx-control-lane::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control-lane::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control-lane[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control-lane[type='email'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
/* @jixoai/css-laws:end:jx-html-alias */
.jx-control-shell.jx-slotted {
padding-inline: var(--jx-inset, 0.75rem);
}
.jx-control-shell .jx-control-lane {
padding-inline: 0;
}
.jx-field {
display: flex;
flex-direction: column;
gap: var(--jx-stack, 0.5rem);
width: 100%;
min-width: 0;
}
.jx-label {
font-family: var(--font-nav);
/* secondary-text is a density ROLE (density-adoption §3): the label
* tracks the ambient scope instead of a fixed 11px (2026-08-29) */
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
cursor: pointer;
}
.jx-error {
display: flex;
align-items: center;
gap: 0.25rem;
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--destructive);
}
.jx-error-mark {
font-weight: bold;
}
/* the shell carries NO chrome itself (final-check ruling): the box
* chrome — border AND fill — lives on a ::before BAND whose height
* matches the -webkit-color-swatch-wrapper (the actual color chip's
* lane). 2026-08-29: the fill moved OFF the shell — an element-painted
* background leaks a full-height rectangle that ears out above/below
* the band on any surface where ambient ≠ --background (cards,
* panels, dark); the band now fills itself.
*
* GEOMETRY LAW (final-check ruling 2, the checkbox/range precedent):
* the chip is a LOCKED size-and-ratio block — height = the hit lane,
* aspect 7:4 (≈4.8rem at the 2.75rem hit — visually balanced, NOT a
* literal width), and the shell is its own SIZE CONTAINER: every
* internal geometry derives from 100cqh, so a density change (or a
* consumer height override) scales the whole chip proportionally —
* the swatch circle, the band, the pill radius, the glyph. The hit
* token sets ONLY the height; nothing else reads it. */
.jx-color-shell {
display: flex;
flex: none;
/* the shell's internal ladder (swatch z1, pipette ::after z2, the
custom-picker overlay z1) is COMPONENT-PRIVATE: container-type
does NOT establish a stacking context (measured, the isolation
clause 2026-09-09), so the shell roots it explicitly — the
deferred class-(a) tail cleared */
isolation: isolate;
/* fit-content protects the ratio-derived width from stretch (grid
tracks, block flow) while aspect-ratio + the locked height keep
it the chip's intrinsic 7:4 */
width: fit-content;
height: var(--jx-hit, 2.5rem);
aspect-ratio: 7 / 4;
container-type: size;
cursor: pointer;
position: relative;
transition: box-shadow 150ms ease-out;
}
.jx-color-shell::before {
content: '';
position: absolute;
inset-inline: 0;
inset-block: calc(100cqh / 6);
border: 1px solid var(--border);
background: var(--background);
pointer-events: none;
corner-left-shape: round;
/* band height = 100cqh − 2×(100cqh/6) = 100cqh × 2/3 — half of it
is the true-semicircle pill radius (no clamp hack) */
border-top-left-radius: calc(100cqh / 3);
border-bottom-left-radius: calc(100cqh / 3);
corner-right-shape: bevel;
/* the right radius rides the SAME cq quantum as the band inset
(100cqh/6 ≈ 8px at the default hit — was var(--radius, 8px),
which froze while every other edge scaled with the container;
B4: no internal dimension outside cq units) */
border-top-right-radius: calc(100cqh / 6);
border-bottom-right-radius: calc(100cqh / 6);
}
.jx-color-expand {
/* both dimensions definite → aspect-ratio yields; the chip keeps
its locked height across the full row.
FLEX PARTICIPATION is re-opened here on purpose: the base shell's
flex:none protects the COMPACT chip, but it also beats any layered
flex utility (this zone is unlayered) — so width:100% alone would
size against the WHOLE flex container and overflow any sibling
(the Tier-1 demo row, 2026-08-29: 77+12+329 > 329). grow reclaims
the full row, shrink shares it; block flow is untouched. */
width: 100%;
flex: 1 1 auto;
}
.jx-color-shell:has([aria-invalid='true'])::before,
.jx-color-shell.jx-invalid::before {
border-style: dashed;
}
.jx-color-shell .jx-color-swatch {
position: relative;
z-index: 1;
flex: none;
/* the chip lane = the container's full height; the swatch circle
inside sizes from the input's own padding (also cqh-relative) */
width: 100cqh;
height: auto;
align-self: stretch;
border: 0;
border-inline-end: 1px solid var(--border);
padding: calc(100cqh / 6);
}
.jx-color-shell .jx-color-swatch:focus-visible {
outline: none;
}
/* clear button: SUPERSEDED by jx-html-clear in the standard layer */
/* @jixoai/css-laws:begin:jx-icon-vocab — GENERATED, do not edit (source: packages/css-laws/src/icon-vocab) */
/* the pipette glyph — an ICON SLOT on the WRAPPER (input[type=color]
* is a replaced element whose ::after is unreliable across engines;
* the label wrapper is non-replaced and paints reliably) */
.jx-color-shell::after {
content: '';
position: absolute;
/* decorative carrier (the law's TRANSIENT INK family) + a ladder
rung — z2 orders against the swatch z1 INSIDE the shell, whose
own isolation: isolate roots the ladder (the isolation clause,
2026-09-09; the shell rule lives in the hand zone above) */
z-index: 2;
/* proportional optics: glyph ≈ 36% of the lane, end inset ≈ 27% —
scale with the container, not with font size */
inset-inline-end: calc(100cqh * 0.27);
top: 50%;
width: calc(100cqh * 0.36);
height: calc(100cqh * 0.36);
translate: 0 -50%;
color: var(--muted-foreground);
background-color: currentColor;
-webkit-mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
pointer-events: none;
}
.jx-color-shell:hover::after {
color: var(--foreground);
}
/* the color-picker chevron — an ICON SLOT (mask, currentColor themes) */
.jx-color-picker-chevron {
display: block;
width: 0.75rem;
height: 0.75rem;
background-color: currentColor;
-webkit-mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
}
/* =====================================================================
Icon vocabulary — the mask/currentColor law. One alpha-only URI per
glyph; the encoded stroke %23000 is an ALPHA SOURCE ONLY. The INK
variants (calendar/clock/valid/invalid) serve UA-shadow pseudos that
reject author mask paint; .dark flips them to %23fff, .jx-light back.
===================================================================== */
@layer theme {
:root {
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* THEME-SCOPED placeholder (canvas bug, Owner 2026-09-04 — same law
as the variant-grammar slots in jixoai.css): custom properties
substitute their var() at the DECLARING element — a :root-only
--jx-placeholder handed every descendant the root's
already-substituted mix, so a scoped .dark/.jx-light
(component-canvas stage, terminal-card, print) flipping
--foreground/--background never re-flipped the placeholder ink
with it. The selector list re-declares the slot ON each theme
scope: one declaration point, zero duplicates */
:root,
.jx-light,
.dark {
--jx-placeholder: color-mix(in oklab, var(--foreground) 40%, var(--background));
}
}
.dark {
/* the author-painted icon set flips to white ink in dark (the
-ink quartet's law extended to the plain slots the input/select
laws consume — black alpha URIs vanish on the dark token sheet) */
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
.jx-light {
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* @jixoai/css-laws:end:jx-icon-vocab */
/* =====================================================================
The zero-class STRUCTURAL input group: a label wrapping a text-like
control AND at least one span composes into the shell — the label
takes the box law, the spans ride as prefix/suffix cells, the
control goes chromeless. NO opt-in class needed.
===================================================================== */
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) {
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
padding-inline: var(--jx-inset, 0.75rem);
cursor: text;
transition: box-shadow 150ms ease-out;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):hover {
box-shadow: var(--shadow-2xs);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > span {
display: inline-flex;
align-items: center;
flex: none;
font-size: var(--jx-text, 0.875rem);
color: var(--muted-foreground);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > input {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
outline: none;
background: transparent;
color: var(--foreground);
font: inherit;
font-size: var(--jx-text, 0.875rem);
padding-inline: 0;
}
/* =====================================================================
Switch size modifiers (face-owned; the standard utility carries the
density-alias default, these opt into explicit sizes)
===================================================================== */
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-sm:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-sm input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 2rem;
--jx-toggle-track: 1.25rem;
--jx-toggle-knob: 0.75rem;
}
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-lg:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-lg input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 3rem;
--jx-toggle-track: 1.5rem;
--jx-toggle-knob: 1.25rem;
}
/* =====================================================================
Bare color input: the locked square standalone (without a .jx-color-
shell wrapper)
===================================================================== */
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: calc(var(--jx-hit, 2.5rem) - 2px);
padding: 2px;
}
/* =====================================================================
Reduced-motion law: the sheet's face-owned transitions neutralize.
===================================================================== */
@media (prefers-reduced-motion: reduce) {
.jx-control,
.jx-control-shell,
.jx-color-shell {
transition: none;
}
}
/* =====================================================================
B · ELEMENT DEFAULTS — the .jx-pure subtree face.
Every rule rides :where(.jx-pure) so the scope class contributes
ZERO specificity inside @layer components: Tailwind utilities
(utilities layer) and any unlayered author css override these
cheaply, and non-Tailwind static consumers override with plain
css. Colors come from tokens or currentColor ONLY — no hardcoded
paint survives a theme flip.
===================================================================== */
@layer components {
/* ---- B0 · the scope root: color-scheme follows the theme classes
the token sheet owns. color-scheme INHERITS — one declaration
themes every native picker, scrollbar and form control in the
subtree: light under :root, dark under .dark (ancestor or self),
forced light under .jx-light. */
:where(.jx-pure):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
/* density adoption (native-contract-fusion Phase 5): the scope
root rides the density interface's text/leading aliases (the
typography LADDER above keeps its fixed steps — declared gap) */
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.6);
}
:where(.dark) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.dark):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
:where(.jx-light) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.jx-light):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
}
/* =====================================================================
B1 · Typography — documented rem steps (the repo ships no
typography size tokens; these literals ARE the scale until a
token ruling lands — do not scatter new sizes elsewhere). The
flow margins are EXPLICIT because preflight zeroes them: a
Tailwind host without this block would render wall-of-text prose.
===================================================================== */
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6):not(.no-jx-pure, .no-jx-pure *) {
margin: 1.5em 0 0.6em;
font-weight: 700;
line-height: 1.25;
color: var(--foreground);
}
:where(.jx-pure) h1:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.875rem;
}
:where(.jx-pure) h2:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.5rem;
}
:where(.jx-pure) h3:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.25rem;
}
:where(.jx-pure) h4:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.125rem;
}
:where(.jx-pure) :where(h5, h6):not(.no-jx-pure, .no-jx-pure *) {
font-size: 1rem;
}
:where(.jx-pure) :where(p, ul, ol, dl, blockquote, pre, table, hr):not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
}
:where(.jx-pure) p:not(.no-jx-pure, .no-jx-pure *) {
line-height: 1.6;
}
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6) :where(p, ul, ol, dl, blockquote, pre, table):first-child:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0;
}
:where(.jx-pure) small:not(.no-jx-pure, .no-jx-pure *) {
font-size: 0.8125rem;
color: var(--muted-foreground);
}
:where(.jx-pure) :where(strong, b):not(.no-jx-pure, .no-jx-pure *) {
font-weight: 700;
}
:where(.jx-pure) blockquote:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-start: 0.875rem;
border-inline-start: 1px solid var(--border);
color: var(--muted-foreground);
}
:where(.jx-pure) :where(code, kbd, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.1em 0.4em;
border: 1px solid var(--border);
background: var(--muted);
font-family: var(--font-mono);
font-size: 0.8125rem;
}
:where(.jx-pure) kbd:not(.no-jx-pure, .no-jx-pure *) {
/* the key cap is ENGRAVED, not lifted (F-2, adversarial-review
2026-09-02 — Owner kbd ruling): --shadow-engrave inset, the
elevation grammar's engrave tier, unified with the registry kbd
component (shadow-engrave). The old `0 1px 0 var(--border)`
lifted-edge dialect is retired — one kbd face across the bare
element and the component. */
box-shadow: var(--shadow-engrave);
}
:where(.jx-pure) pre:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.75rem 1rem;
border: 1px solid var(--border);
background: var(--background);
overflow: auto;
font-family: var(--font-mono);
font-size: 0.8125rem;
line-height: 1.55;
}
/* the code-in-pre lane drops its inline box — the pre owns the box */
:where(.jx-pure) pre :where(code, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0;
border: 0;
background: transparent;
font-size: inherit;
}
:where(.jx-pure) mark:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.05em 0.25em;
background: color-mix(in oklab, var(--secondary) 45%, var(--background));
color: var(--foreground);
}
:where(.jx-pure) hr:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 1.5rem;
border: 0;
border-top: 1px solid var(--border);
}
/* =====================================================================
B2 · Links — the site link law (press-button link variant):
primary text, no underline at rest, underline on hover. Nav links
read as chrome, not prose: foreground at rest, primary + underline
as the hover cue.
===================================================================== */
:where(.jx-pure) a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-underline-offset: 4px;
}
:where(.jx-pure) a:hover:not(.no-jx-pure, .no-jx-pure *) {
text-decoration-line: underline;
}
:where(.jx-pure) nav a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--foreground);
}
:where(.jx-pure) nav a:hover:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-decoration-line: underline;
}
/* =====================================================================
B3 · Buttons — the .jx-press physics restated element-scoped
(hover grows the token shadow + bg-muted; active presses +1px
into the page with the *-press twin — same variable contract,
no WAAPI, no second geometry law). .jx-button is the EXPLICIT
channel for link-look buttons (Codex D2: never auto-style
a[role=button] — CSS cannot add command semantics). Focus is
deliberately NOT set here: the host's focus law owns it (site
base layer paints a/button; static pages keep the UA ring).
===================================================================== */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *) {
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.375rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 1rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
line-height: 1.45;
text-decoration: none;
cursor: pointer;
box-shadow: var(--jx-press-shadow, var(--shadow-xs));
transition:
translate 150ms ease-out,
box-shadow 150ms ease-out,
background-color 150ms ease-out,
border-color 150ms ease-out,
color 150ms ease-out;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):hover:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
box-shadow: var(--jx-press-shadow-hover, var(--shadow-sm));
}
/* :active LAST — at equal specificity the later rule wins the hover pose */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: 1px 1px;
box-shadow: var(--jx-press-shadow-active, var(--shadow-sm-press));
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
cursor: not-allowed;
box-shadow: none;
}
/* =====================================================================
B4+B5 · form controls = @apply applications of the standard
layer (the 13-type allowlist rides each selector; the number lane
keeps the PLATFORM stepper by sharing jx-html-input; checkbox
excludes [role=switch] so the switch gets its own utility) ----- */
/* GENERATED between the markers (css-laws V3): the bare-element
defaults — same declaration source as the .jx-html-* classes,
serialized as element-default rules under :where(.jx-pure) */
/* @jixoai/css-laws:begin:jx-html-face — GENERATED, do not edit (source: packages/css-laws/src/laws) */
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-textarea-min, 5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
height: auto;
resize: vertical;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
--jx-icon-chevron-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
cursor: pointer;
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):disabled, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
@supports not selector(::-moz-range-progress) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
background-image: var(--jx-icon-chevron, var(--jx-icon-chevron-svg));
background-position: right var(--jx-inset, 0.75rem) center;
background-size: var(--jx-icon, 1.25rem);
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
filter: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]) {
min-height: 5.75rem;
padding-block: 0.375rem 0.5rem;
cursor: default;
background-image: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
cursor: pointer;
transition: background-color 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate::before {
opacity: 1;
transform: rotate(0deg);
clip-path: polygon(10% 40%, 10% 60%, 45% 60%, 55% 60%, 90% 60%, 90% 40%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked, :where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate {
background: var(--primary);
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 50%;
background: var(--background);
cursor: pointer;
transition: border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
content: none;
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::after {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
border-radius: 50%;
background: var(--primary);
transform: scale(0);
transition: transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::after {
transform: scale(1);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--background);
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
position: relative;
width: var(--jx-toggle-width, 2.5rem);
height: var(--jx-toggle-track, 1.5rem);
margin: 0;
flex: none;
padding: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
border: 0;
box-shadow: 0 0 0 1px var(--border) inset;
border-radius: calc(infinity * 1px);
background: var(--muted);
cursor: pointer;
transition: background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
inset-block: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inset-inline-start: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inline-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
block-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
border-radius: calc(infinity * 1px);
border: var(--jx-toggle-knob-border, 1px) solid var(--jx-toggle-knob-border-color, var(--primary));
background: var(--background);
transform: translateX(0);
transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1), background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), border-color 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
transform: translateX(calc(var(--jx-toggle-width, 2.5rem) - var(--jx-toggle-track, 1.5rem)));
background: var(--primary-foreground);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
box-shadow: 0 0 0 1px var(--primary) inset;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)) {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch-wrapper {
padding: 0;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-moz-color-swatch {
border: 0;
border-radius: 0;
}
/* @jixoai/css-laws:end:jx-html-face */
/* ---- B6 · label / fieldset / legend (face-owned; not form-
control law — the one-opacity-owner disabled law) -------------
===================================================================== */
:where(.jx-pure) label:not(.no-jx-pure, .no-jx-pure *) {
cursor: pointer;
}
:where(.jx-pure) fieldset:not(.no-jx-pure, .no-jx-pure *) {
min-width: 0;
margin-block: 0.75rem;
padding: 0.875rem 1rem 1rem;
border: 1px solid var(--border);
border-radius: 0;
}
:where(.jx-pure) fieldset:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* ONE opacity owner per subtree (Codex review A3): the group dims to
.5 and the controls inside stay at 1 — two stacked .5 layers
composite to ~.25 and the contrast collapses */
:where(.jx-pure) fieldset:disabled :where(input, textarea, select, button):not(.no-jx-pure, .no-jx-pure *) {
opacity: 1;
cursor: not-allowed;
}
:where(.jx-pure) legend:not(.no-jx-pure, .no-jx-pure *) {
padding-inline: 0.5rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* =====================================================================
B7 · details / summary — document-flow disclosure ONLY (dialog /
popover / tooltip stay Tier-2, Codex D3). Static marker swap, no
open/close animation (progressive enhancement deferred); the
visible focus ring is never replaced by the marker.
===================================================================== */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *) {
display: flex;
align-items: center;
gap: 0.625rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
font-size: 0.875rem;
list-style: none;
cursor: pointer;
transition:
border-color 150ms ease-out,
box-shadow 150ms ease-out;
}
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::-webkit-details-marker {
display: none;
}
/* the marker: a bordered square holding + / − (static swap) */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '+';
box-sizing: border-box;
display: grid;
place-items: center;
width: 1.125rem;
height: 1.125rem;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--muted-foreground);
font-family: var(--font-nav);
font-size: 12px;
line-height: 1;
}
:where(.jx-pure) details[open] > summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '−';
}
:where(.jx-pure) summary:hover:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--primary); /* leans like the checkbox border */
}
:where(.jx-pure) summary:focus-visible:not(.no-jx-pure, .no-jx-pure *) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) details > * + *:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.5rem;
}
/* =====================================================================
B8 · lists / dl — restore the document-flow markers preflight
removes (classless parity) and theme them; nav's link law lives
in B2.
===================================================================== */
:where(.jx-pure) ul:not(.no-jx-pure, .no-jx-pure *) {
list-style: disc;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) ol:not(.no-jx-pure, .no-jx-pure *) {
list-style: decimal;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) li:not(.no-jx-pure, .no-jx-pure *)::marker {
color: var(--muted-foreground);
}
:where(.jx-pure) dl:not(.no-jx-pure, .no-jx-pure *) {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.375rem 1rem;
}
:where(.jx-pure) dt:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
:where(.jx-pure) dd:not(.no-jx-pure, .no-jx-pure *) {
margin: 0;
}
/* =====================================================================
B9 · Tables — the bordered grid law.
===================================================================== */
:where(.jx-pure) table:not(.no-jx-pure, .no-jx-pure *) {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
:where(.jx-pure) caption:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.375rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
caption-side: bottom;
text-align: start;
}
:where(.jx-pure) :where(th, td):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
text-align: start;
}
:where(.jx-pure) th:not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
font-family: var(--font-nav);
font-size: 11px;
font-weight: 400;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
white-space: nowrap;
}
:where(.jx-pure) tbody tr:hover:not(.no-jx-pure, .no-jx-pure *) {
background: color-mix(in oklab, var(--muted) 26%, transparent);
}
/* =====================================================================
B10 · progress / meter / output (Owner completion round, 2026-08-24:
the Codex D6 deferral is overruled — the contracts exist now).
progress: the range-track geometry (8px bordered box, primary
fill); indeterminate trades the fill for a sliding stripe, fully
static under reduced motion. meter: the same box with the
SEMANTIC token mapping — optimum=primary, suboptimal=secondary,
even-less-good=destructive (no hardcoded traffic lights). output:
the mono result lane. Engine pseudos live in SEPARATE rules (the
R1 law: a shared -moz list is dropped whole by Chromium).
===================================================================== */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *) {
display: block;
box-sizing: border-box;
width: 100%;
height: 0.5rem; /* the 8px track family (incl. borders) */
margin: 0;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
appearance: none;
-webkit-appearance: none;
overflow: hidden;
}
:where(.jx-pure) progress:disabled:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* chromium: the track pseudo + the value pseudo */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-bar {
background: var(--background);
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-value {
background: var(--primary);
transition: width 150ms ease-out;
}
/* indeterminate: no percent exists — a muted stripe slides across.
The stripe rides the ELEMENT's own background, never the UA
pseudos: engines reject author paint/animation on progress
pseudos exactly like the number spinners (Codex r4 R4-1 — the
pseudo path compiled but never animated). Part C parks it under
reduced motion. */
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *) {
background:
linear-gradient(in oklab, var(--muted), var(--muted)) 0 0 / 40% 100% no-repeat,
var(--background);
animation: jx-progress-slide 1.2s linear infinite;
}
/* firefox: the element is the track; the bar pseudo is the value */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: var(--primary);
}
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: transparent; /* the element's stripe owns the paint */
}
/* meter: the semantic three-state fill (token-mapped, monochrome law) */
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-bar {
background: var(--background);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-optimum-value {
background: var(--primary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-suboptimum-value {
background: var(--secondary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-even-less-good-value {
background: var(--destructive);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--primary);
}
:where(.jx-pure) meter:-moz-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--secondary);
}
:where(.jx-pure) meter:-moz-sub-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--destructive);
}
/* the stripe keyframes live OUTSIDE the layer's rule bodies… they
are defined once here (keyframes are global; the jx- prefix keeps
the namespace) — declared at the layer's end so both engine rules
above can reference them */
}
@keyframes jx-progress-slide {
from {
background-position: -40% 0, 0 0;
}
to {
background-position: 140% 0, 0 0;
}
}
@layer components {
/* output: the calculation result lane — mono, foreground, inline */
:where(.jx-pure) output:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-mono);
font-size: 0.875rem;
color: var(--foreground);
}
/* =====================================================================
B11 · figure / media — the documentation flow. figure carries the
flow margin + the bordered plate; figcaption rides the caption
law (nav font, small caps, muted, below). Media never overflows
its lane.
===================================================================== */
:where(.jx-pure) :where(img, video):not(.no-jx-pure, .no-jx-pure *) {
max-width: 100%;
height: auto;
}
:where(.jx-pure) figure:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.375rem;
max-width: 100%;
}
:where(.jx-pure) figure > :where(img, video, svg, pre, table):not(.no-jx-pure, .no-jx-pure *) {
border: 1px solid var(--border);
}
:where(.jx-pure) figcaption:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* ---- B13 · switch = @apply application (the ONE input law;
[role=switch] discriminates it from the checkbox) ------------- */
/* the label posture: a wrapping label dims with its input */
:where(.jx-pure) label:has(> input[type='checkbox'][role='switch']):not(.no-jx-pure, .no-jx-pure *) {
display: inline-flex;
align-items: center;
gap: var(--jx-gap, 0.5rem);
cursor: pointer;
user-select: none;
min-block-size: var(--jx-hit, 2.5rem);
&:has(input:disabled) {
cursor: not-allowed;
opacity: 0.5;
}
}
/* =====================================================================
B14 · validation states — the Pico state matrix on the SEMANTIC
palette (openspec D5): aria-invalid='false' leans --success ('✓'
ink + success border + success hover lean); aria-invalid='true'
flips every accent to --error (dashed lanes + '!' ink, checked
fills, the radio DOT, switch track, range fill + thumb).
--destructive is NOT used here — it stays the monochrome
inversion pair for destructive actions. Native :invalid stays
deliberately unhooked (no empty-required surprises).
===================================================================== */
/* lanes: border-color states + the ink glyphs */
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
background-image: var(--jx-icon-invalid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: 2rem;
background-image: var(--jx-icon-valid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
/* checkbox / radio: the checked accent flips to error */
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:indeterminate:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::after {
background: var(--error-foreground);
}
:where(.jx-pure) input[type='checkbox'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success); /* the valid lean */
}
/* switch: the checked track flips */
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::before {
border-color: transparent;
}
/* range: fill + thumb flip */
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
--jx-slider-fill-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-webkit-slider-thumb {
border-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-moz-range-thumb {
background: var(--error);
}
}
/* =====================================================================
B12 · the reverse scope — .no-jx-pure (Owner third revision,
2026-08-24): the r8/r9 `all: revert !important` hatch was too
violent — it also rolled back the HOST's own utilities and inline
styles. Every face rule now carries the exclusion on its subject:
:not(.no-jx-pure, .no-jx-pure *) — an element that IS, or lives
inside, a no-jx-pure subtree never receives the face; everything
the host authored there is untouched. Part A opt-in classes still
work inside islands (author intent, not face paint). INHERITED
properties (color-scheme, custom property tokens) keep flowing
through islands from ancestors — the exclusion is element-level
paint, never a war against the page's theme or the host.
=====================================================================
*/
/* =====================================================================
C · DEGRADATION LAWS — motion and forced colors.
===================================================================== */
/* Reduced motion: FULL STILLNESS, not zero-duration animation (Codex
review B): every Part B transition goes none AND the interactive
displacements (the press translate, the thumb press transform) are
pinned back to their rest poses so nothing ever moves. */
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) :where(textarea, select):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
/* engine pseudos NEVER share a selector list — a non-forgiving list
with an unknown -moz pseudo is dropped WHOLE by Chromium (Codex
r2 R1); one rule per engine surface */
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
/* the indeterminate stripe parks: element animation off (the
authored -moz pseudo animation is likewise killed — one rule per
surface, and the -moz one stands alone) */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *) {
animation: none;
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
animation: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
:where(.jx-pure) input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
transition: none;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: none;
}
}
/* Forced colors (Windows High Contrast & friends): the custom-painted
controls revert to appearance:auto so the SYSTEM palette and glyphs
speak — author paint would flatten into the forced canvas and lose
the checked/unchecked distinction entirely. Box laws (borders,
outlines) survive: forced-colors keeps author borders as system
colors. The opt-in select ALSO drops its gradient chevron or the
restored platform arrow would double up with the leftover paint. */
@media (forced-colors: active) {
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='range']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='color']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select:not(.no-jx-pure, .no-jx-pure *) {
appearance: auto;
-webkit-appearance: auto;
background-image: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before,
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
content: none;
}
}
/* ==== BEGIN GENERATED · jx-auto-dark — scripts/gen-jx-auto-dark.mjs (do not hand-edit) ==== */
/* Derived 1:1 from jixoai.css's .dark block (single source). The gate
rides :where() so the whole variant stays maximally overridable; it
never fires where an explicit .dark already owns the theme, nor
inside .jx-light islands. Mount: <html class="jx-pure jx-auto-dark"> */
@media (prefers-color-scheme: dark) {
:where(.jx-auto-dark):not(.dark, .jx-light *) {
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--terminal: oklch(0.2 0 0);
--terminal-foreground: oklch(1 0 0);
--terminal-hover: color-mix(in oklab, var(--terminal-foreground) 14%, var(--terminal));
--terminal-muted: color-mix(in oklab, var(--terminal-foreground) 8%, var(--terminal));
--card: oklch(0.3211 0 0);
--card-foreground: oklch(1 0 0);
--popover: oklch(0.3211 0 0);
--popover-foreground: oklch(1 0 0);
/* the primary hue drifts -4° toward dark, mirroring the reference */
--primary: oklch(0.7044 0.1872 calc(var(--brand-hue) - 4));
--primary-foreground: oklch(0 0 0);
--primary-text: var(--primary);
--secondary: oklch(0.9691 0.2005 109.6228);
--secondary-foreground: oklch(0 0 0);
--muted: oklch(0.2178 0 0);
--muted-foreground: oklch(0.8452 0 0);
--accent: oklch(0.6755 0.1765 252.2592);
--accent-foreground: oklch(0 0 0);
--destructive: oklch(1 0 0);
--destructive-foreground: oklch(0 0 0);
--border: oklch(1 0 0);
--input: oklch(1 0 0);
--ring: var(--primary);
--success: oklch(0.72 0.16 145);
--success-foreground: oklch(0 0 0);
--warning: oklch(0.78 0.17 85);
--warning-foreground: oklch(0 0 0);
--info: oklch(0.74 0.14 245);
--info-foreground: oklch(0 0 0);
--error: oklch(0.72 0.16 25);
--error-foreground: oklch(0 0 0);
--chart-1: var(--primary);
--chart-2: var(--success);
--chart-3: var(--info);
--chart-4: var(--warning);
--chart-5: var(--error);
--shadow-color: hsl(0 0% 100%);
/* shadow GEOMETRY rides the light baseline rung for rung (Owner ruling,
2026-09-01: sizes must not drift between themes — only the INK
inverts to white; the old 4px-everywhere small rungs were copy-paste
drift, not design) */
--shadow-2xs: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-xs: 2px 2px 0px 0px hsl(0 0% 100% / 0.5);
/* ink compensation (F-11, 2026-09-02): the second layer's alpha is
deliberately NOT mirrored (0.5 light / 1.0 dark) — the black ring
rides directly on the white offset over a black ground, where
half-alpha would read as a gray smear; geometry stays rung for
rung, only the ink density compensates */
--shadow-sm: 2px 2px 0px 0px hsl(0 0% 100% / 1), 1px 1px 0px 1px hsl(0 0% 0% / 1);
--shadow: 4px 4px 0px 0px hsl(0 0% 100% / 1);
--shadow-md: 4px 4px 0px 0px hsl(0 0% 100% / 1), 4px 2px 4px -1px hsl(0 0% 0% / 1);
/* --shadow-lg removed with the light block (F-10) */
/* press poses — same minus-1px law as the light block above */
--shadow-xs-press: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-sm-press: 1px 1px 0px 0px hsl(0 0% 100% / 1), 0px 0px 0px 1px hsl(0 0% 0% / 1);
--shadow-md-press: 3px 3px 0px 0px hsl(0 0% 100% / 1), 3px 1px 4px -1px hsl(0 0% 0% / 1);
/* elevation grammar, dark side: same geometry rung for rung, the
ink inverted to white (the white-shadow law); --shadow-paper is
theme-INDEPENDENT (paper stays white — see the light block).
The engrave duet inverts BOTH inks (the law's mechanical face —
the glow wall's black on dark reads as the carved sheen) */
--jx-engrave-shade: hsl(0 0% 100% / 0.4);
--jx-engrave-glow: hsl(0 0% 0% / 0.96);
--shadow-engrave: inset 1px 1px 0px 0px var(--jx-engrave-shade),
inset -1px -1px 0px 0px var(--jx-engrave-glow);
--shadow-well: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--shadow-well-hover: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.28);
/* floating-surface law, dark side: inverted — scrims and the shadow
layer are semi-transparent WHITE and BRIGHTEN (the white-shadow
law; same 0.32 veil strength as light mode's black) */
--scrim: hsl(0 0% 100% / 0.1);
--surface-shadow: oklch(0 0 0 / 0.32); /* black — r14-17, Owner */
/* ── the surface ladder, dark side (explicit-props §7 / task 1.1):
the M3 dark law — shadows are weak here, the STEPS carry the
hierarchy; the rungs LIGHTEN upward, away from the page void,
and stay below --card (0.3211 — the existing panel tokens keep
their place above the ladder). 减色墨律: role steps, never
overlays. This block feeds the generated prefers-color-scheme
projection in jx-pure.css (gen-jx-auto-dark — single source). */
--surface: var(--background);
--surface-container-lowest: oklch(0.115 0 0);
--surface-container-low: oklch(0.185 0 0);
--surface-container: oklch(0.205 0 0);
--surface-container-high: oklch(0.245 0 0);
--surface-container-highest: oklch(0.29 0 0);
--surface-concave: var(--background);
/* ── the elevation level table, dark side (explicit-props §0.1/§7 /
task 1.2): geometry pinned rung for rung with light (the
2026-09-01 law — sizes never drift between themes), the ink
inverted to white at reduced alpha — the soft-lens compensation
(dark hierarchy rides the LADDER; full-alpha white glow through
a 12px blur would wash it). level-1 keeps the inset duet's
single shade wall at the well-tier strength. */
--jx-elevation-level-1-shadow:
inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--jx-elevation-level-1-surface: var(--surface-concave);
--jx-elevation-level0-shadow: none;
--jx-elevation-level0-surface: var(--surface);
--jx-elevation-level1-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 1px 3px 1px hsl(0 0% 100% / 0.08);
--jx-elevation-level1-surface: var(--surface-container-lowest);
--jx-elevation-level2-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 2px 6px 2px hsl(0 0% 100% / 0.08);
--jx-elevation-level2-surface: var(--surface-container-low);
--jx-elevation-level3-shadow:
0px 1px 3px 0px hsl(0 0% 100% / 0.16),
0px 4px 8px 3px hsl(0 0% 100% / 0.08);
--jx-elevation-level3-surface: var(--surface-container);
--jx-elevation-level4-shadow:
0px 2px 3px 0px hsl(0 0% 100% / 0.16),
0px 6px 10px 4px hsl(0 0% 100% / 0.08);
--jx-elevation-level4-surface: var(--surface-container-high);
--jx-elevation-level5-shadow:
0px 4px 4px 0px hsl(0 0% 100% / 0.16),
0px 8px 12px 6px hsl(0 0% 100% / 0.08);
--jx-elevation-level5-surface: var(--surface-container-highest);
/* the color axis' effective carrier — dark's own --primary (the
hue-drifted one; re-declared per theme scope, the canvas-bug
law) */
--jx-color-effective: var(--primary);
color-scheme: dark;
}
/* the scope-root companion: without it B0's color-scheme: light would
out-shout the inherited root scheme and native pickers/scrollbars
would stay light under dark tokens (the inverted-A2 bug) */
:where(.jx-auto-dark) :where(.jx-pure):not(.jx-light, .jx-light *):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
}
/* ==== END GENERATED · jx-auto-dark ==== */
demo
Tables
The bordered grid law: 1px var(--border) cells, nav-font small-caps headers on a muted fill, hover leans rows via a token mix. Caption rides the bottom as the documentation voice.
jx-pure · tables
The bordered grid law: 1px var(--border) cells, nav-font small-caps headers on a muted fill, hover leans rows via a token mix; the caption rides the bottom as the documentation voice.
| element | chromium | firefox | webkit |
|---|---|---|---|
| checkbox / radio | verified: clip-path + dot | same law, unverified build | same law, unverified build |
| range | verified: webkit pseudos | -moz pseudos authored | webkit pseudos authored |
| date/time indicator | verified: mask glyph | native indicator | native indicator |
| select.jx-select | verified: gradient chevron | same law, unverified build | same law, unverified build |
| progress / meter | verified: track family + token fills | -moz bar pseudos authored | native bar (webkit pseudos) |
/**
* jx-pure — the face of jixoai-ui (registry/files/theme/jx-pure.css).
*
* V3 (css-laws, 2026-08-28): the native form-control laws are
* SINGLE-SOURCED as typed TS objects in packages/css-laws/src/laws.
* THIS file carries two GENERATED projections of that source (the
* @apply chain is retired — TW4 dev did not reliably emit complex
* utilities onto element selectors):
* Part A slot — the Tier-2 opt-in classes (.jx-control, .jx-slider,
* …), unlayered by design (they beat layered utilities)
* Part B slot — the bare-element defaults under :where(.jx-pure),
* inside this sheet's @layer components
* Regenerate after editing laws: npx tsx packages/css-laws/src/build.ts
* Non-form-control face laws (typography, links, buttons, fieldset,
* details, lists, tables, progress, figure, validation matrix, scope
* law) remain face-authored below.
*
* A · opt-in classes = GENERATED alias slot (css-laws)
* B · element defaults = GENERATED face slot (css-laws) + face-authored laws
* C · degradation laws (face-owned transitions only)
* D · auto-dark (GENERATED by scripts/gen-jx-auto-dark.mjs)
*
* Scope law: .jx-pure is a subtree wrapper — it never reaches into
* shadow roots (CustomElements must @import this sheet inside their
* own shadow style). dialog/popover/tooltip are Tier-2 territory.
*/
/* =====================================================================
A · OPT-IN CLASSES — @apply applications of the standard layer
(the declarations live once in jixoai.css; these selectors only
bind them to the opt-in vocabulary)
===================================================================== */
/* opt-in classes = GENERATED applications of the standard layer
(the declarations live once in packages/css-laws/src/laws; these
selectors bind them to the opt-in vocabulary — Tier-2, unlayered
by design: they beat layered utilities) */
/* @jixoai/css-laws:begin:jx-html-alias — GENERATED, do not edit (source: packages/css-laws/src/laws) */
.jx-slider {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
.jx-slider::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider:dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
.jx-slider[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
.jx-slider:focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
.jx-slider:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-color-swatch {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
.jx-color-swatch::-webkit-color-swatch-wrapper {
padding: 0;
}
.jx-color-swatch::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
.jx-color-swatch::-moz-color-swatch {
border: 0;
border-radius: 0;
}
.jx-tgroup {
corner-shape: var(--corner-shape, bevel);
display: inline-flex;
width: fit-content;
flex-wrap: wrap;
overflow: hidden;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--card);
box-shadow: var(--shadow-2xs);
}
.jx-tgroup> label {
display: inline-flex;
align-items: center;
min-block-size: var(--jx-hit, 2.5rem);
padding-block: calc((var(--jx-hit, 2.5rem) - var(--jx-line, 1.25rem)) / 2);
padding-inline: var(--jx-inset, 0.75rem);
font-family: var(--font-nav);
font-size: var(--jx-text, 0.8125rem);
line-height: var(--jx-line, 1.25rem);
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted-foreground);
background-color: transparent;
border-inline-end: 1px solid var(--border);
cursor: pointer;
user-select: none;
transition: color 150ms ease-out, background-color 150ms ease-out;
}
.jx-tgroup> label:last-child {
border-inline-end: 0;
}
.jx-tgroup> label:not(:has(input:disabled)):hover {
color: var(--foreground);
}
.jx-tgroup> label:has(input:checked) {
background-color: var(--primary);
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:checked):not(:has(input:disabled)):hover {
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-tgroup> label:has(input:disabled) {
cursor: not-allowed;
opacity: 0.45;
}
.jx-tgroup> label > input {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.jx-tgroup[data-chrome='bare'] {
border: 0;
background: transparent;
box-shadow: none;
border-radius: 0;
overflow: visible;
}
.jx-tgroup[data-chrome='bare'] > label {
border-inline-end: 0;
flex: 1 1 auto;
justify-content: center;
}
.jx-tgroup[data-chrome='bare'] > label:not(:has(input:disabled)):hover {
color: var(--foreground);
background-color: color-mix(in oklab, var(--muted) 55%, transparent);
}
@media (prefers-reduced-motion: reduce) {
.jx-tgroup> label {
transition: none;
}
}
.jx-control {
box-sizing: border-box;
display: block;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding: var(--jx-gap, 0.5rem) var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font-size: var(--jx-text, 0.875rem);
color-scheme: light;
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control:focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
.jx-control:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-control[aria-invalid='true'] {
border-style: dashed;
border-color: var(--error);
color: var(--error);
}
.jx-control[aria-invalid='false'] {
border-color: var(--primary);
}
.jx-control::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control[type='email'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
.jx-control {
transition: none;
}
}
.jx-control-shell {
box-sizing: border-box;
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
font-size: var(--jx-text, 0.875rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
box-shadow: var(--shadow-well);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control-shell:has(> .jx-html-clear:last-child) {
padding-inline-end: 0;
}
.jx-control-shell:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control-shell:has(:focus) {
border-color: var(--ring);
}
.jx-control-shell:has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-control-shell:has([aria-invalid='true']), .jx-control-shell.jx-invalid {
border-style: dashed;
}
.jx-control-shell:has(:disabled) {
border-color: var(--muted);
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
.jx-control-shell {
transition: none;
}
}
.jx-control-lane {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
padding: 0;
outline: none;
background: transparent;
color: var(--foreground);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
}
.jx-control-lane::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control-lane::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control-lane[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control-lane[type='email'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
/* @jixoai/css-laws:end:jx-html-alias */
.jx-control-shell.jx-slotted {
padding-inline: var(--jx-inset, 0.75rem);
}
.jx-control-shell .jx-control-lane {
padding-inline: 0;
}
.jx-field {
display: flex;
flex-direction: column;
gap: var(--jx-stack, 0.5rem);
width: 100%;
min-width: 0;
}
.jx-label {
font-family: var(--font-nav);
/* secondary-text is a density ROLE (density-adoption §3): the label
* tracks the ambient scope instead of a fixed 11px (2026-08-29) */
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
cursor: pointer;
}
.jx-error {
display: flex;
align-items: center;
gap: 0.25rem;
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--destructive);
}
.jx-error-mark {
font-weight: bold;
}
/* the shell carries NO chrome itself (final-check ruling): the box
* chrome — border AND fill — lives on a ::before BAND whose height
* matches the -webkit-color-swatch-wrapper (the actual color chip's
* lane). 2026-08-29: the fill moved OFF the shell — an element-painted
* background leaks a full-height rectangle that ears out above/below
* the band on any surface where ambient ≠ --background (cards,
* panels, dark); the band now fills itself.
*
* GEOMETRY LAW (final-check ruling 2, the checkbox/range precedent):
* the chip is a LOCKED size-and-ratio block — height = the hit lane,
* aspect 7:4 (≈4.8rem at the 2.75rem hit — visually balanced, NOT a
* literal width), and the shell is its own SIZE CONTAINER: every
* internal geometry derives from 100cqh, so a density change (or a
* consumer height override) scales the whole chip proportionally —
* the swatch circle, the band, the pill radius, the glyph. The hit
* token sets ONLY the height; nothing else reads it. */
.jx-color-shell {
display: flex;
flex: none;
/* the shell's internal ladder (swatch z1, pipette ::after z2, the
custom-picker overlay z1) is COMPONENT-PRIVATE: container-type
does NOT establish a stacking context (measured, the isolation
clause 2026-09-09), so the shell roots it explicitly — the
deferred class-(a) tail cleared */
isolation: isolate;
/* fit-content protects the ratio-derived width from stretch (grid
tracks, block flow) while aspect-ratio + the locked height keep
it the chip's intrinsic 7:4 */
width: fit-content;
height: var(--jx-hit, 2.5rem);
aspect-ratio: 7 / 4;
container-type: size;
cursor: pointer;
position: relative;
transition: box-shadow 150ms ease-out;
}
.jx-color-shell::before {
content: '';
position: absolute;
inset-inline: 0;
inset-block: calc(100cqh / 6);
border: 1px solid var(--border);
background: var(--background);
pointer-events: none;
corner-left-shape: round;
/* band height = 100cqh − 2×(100cqh/6) = 100cqh × 2/3 — half of it
is the true-semicircle pill radius (no clamp hack) */
border-top-left-radius: calc(100cqh / 3);
border-bottom-left-radius: calc(100cqh / 3);
corner-right-shape: bevel;
/* the right radius rides the SAME cq quantum as the band inset
(100cqh/6 ≈ 8px at the default hit — was var(--radius, 8px),
which froze while every other edge scaled with the container;
B4: no internal dimension outside cq units) */
border-top-right-radius: calc(100cqh / 6);
border-bottom-right-radius: calc(100cqh / 6);
}
.jx-color-expand {
/* both dimensions definite → aspect-ratio yields; the chip keeps
its locked height across the full row.
FLEX PARTICIPATION is re-opened here on purpose: the base shell's
flex:none protects the COMPACT chip, but it also beats any layered
flex utility (this zone is unlayered) — so width:100% alone would
size against the WHOLE flex container and overflow any sibling
(the Tier-1 demo row, 2026-08-29: 77+12+329 > 329). grow reclaims
the full row, shrink shares it; block flow is untouched. */
width: 100%;
flex: 1 1 auto;
}
.jx-color-shell:has([aria-invalid='true'])::before,
.jx-color-shell.jx-invalid::before {
border-style: dashed;
}
.jx-color-shell .jx-color-swatch {
position: relative;
z-index: 1;
flex: none;
/* the chip lane = the container's full height; the swatch circle
inside sizes from the input's own padding (also cqh-relative) */
width: 100cqh;
height: auto;
align-self: stretch;
border: 0;
border-inline-end: 1px solid var(--border);
padding: calc(100cqh / 6);
}
.jx-color-shell .jx-color-swatch:focus-visible {
outline: none;
}
/* clear button: SUPERSEDED by jx-html-clear in the standard layer */
/* @jixoai/css-laws:begin:jx-icon-vocab — GENERATED, do not edit (source: packages/css-laws/src/icon-vocab) */
/* the pipette glyph — an ICON SLOT on the WRAPPER (input[type=color]
* is a replaced element whose ::after is unreliable across engines;
* the label wrapper is non-replaced and paints reliably) */
.jx-color-shell::after {
content: '';
position: absolute;
/* decorative carrier (the law's TRANSIENT INK family) + a ladder
rung — z2 orders against the swatch z1 INSIDE the shell, whose
own isolation: isolate roots the ladder (the isolation clause,
2026-09-09; the shell rule lives in the hand zone above) */
z-index: 2;
/* proportional optics: glyph ≈ 36% of the lane, end inset ≈ 27% —
scale with the container, not with font size */
inset-inline-end: calc(100cqh * 0.27);
top: 50%;
width: calc(100cqh * 0.36);
height: calc(100cqh * 0.36);
translate: 0 -50%;
color: var(--muted-foreground);
background-color: currentColor;
-webkit-mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
pointer-events: none;
}
.jx-color-shell:hover::after {
color: var(--foreground);
}
/* the color-picker chevron — an ICON SLOT (mask, currentColor themes) */
.jx-color-picker-chevron {
display: block;
width: 0.75rem;
height: 0.75rem;
background-color: currentColor;
-webkit-mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
}
/* =====================================================================
Icon vocabulary — the mask/currentColor law. One alpha-only URI per
glyph; the encoded stroke %23000 is an ALPHA SOURCE ONLY. The INK
variants (calendar/clock/valid/invalid) serve UA-shadow pseudos that
reject author mask paint; .dark flips them to %23fff, .jx-light back.
===================================================================== */
@layer theme {
:root {
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* THEME-SCOPED placeholder (canvas bug, Owner 2026-09-04 — same law
as the variant-grammar slots in jixoai.css): custom properties
substitute their var() at the DECLARING element — a :root-only
--jx-placeholder handed every descendant the root's
already-substituted mix, so a scoped .dark/.jx-light
(component-canvas stage, terminal-card, print) flipping
--foreground/--background never re-flipped the placeholder ink
with it. The selector list re-declares the slot ON each theme
scope: one declaration point, zero duplicates */
:root,
.jx-light,
.dark {
--jx-placeholder: color-mix(in oklab, var(--foreground) 40%, var(--background));
}
}
.dark {
/* the author-painted icon set flips to white ink in dark (the
-ink quartet's law extended to the plain slots the input/select
laws consume — black alpha URIs vanish on the dark token sheet) */
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
.jx-light {
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* @jixoai/css-laws:end:jx-icon-vocab */
/* =====================================================================
The zero-class STRUCTURAL input group: a label wrapping a text-like
control AND at least one span composes into the shell — the label
takes the box law, the spans ride as prefix/suffix cells, the
control goes chromeless. NO opt-in class needed.
===================================================================== */
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) {
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
padding-inline: var(--jx-inset, 0.75rem);
cursor: text;
transition: box-shadow 150ms ease-out;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):hover {
box-shadow: var(--shadow-2xs);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > span {
display: inline-flex;
align-items: center;
flex: none;
font-size: var(--jx-text, 0.875rem);
color: var(--muted-foreground);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > input {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
outline: none;
background: transparent;
color: var(--foreground);
font: inherit;
font-size: var(--jx-text, 0.875rem);
padding-inline: 0;
}
/* =====================================================================
Switch size modifiers (face-owned; the standard utility carries the
density-alias default, these opt into explicit sizes)
===================================================================== */
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-sm:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-sm input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 2rem;
--jx-toggle-track: 1.25rem;
--jx-toggle-knob: 0.75rem;
}
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-lg:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-lg input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 3rem;
--jx-toggle-track: 1.5rem;
--jx-toggle-knob: 1.25rem;
}
/* =====================================================================
Bare color input: the locked square standalone (without a .jx-color-
shell wrapper)
===================================================================== */
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: calc(var(--jx-hit, 2.5rem) - 2px);
padding: 2px;
}
/* =====================================================================
Reduced-motion law: the sheet's face-owned transitions neutralize.
===================================================================== */
@media (prefers-reduced-motion: reduce) {
.jx-control,
.jx-control-shell,
.jx-color-shell {
transition: none;
}
}
/* =====================================================================
B · ELEMENT DEFAULTS — the .jx-pure subtree face.
Every rule rides :where(.jx-pure) so the scope class contributes
ZERO specificity inside @layer components: Tailwind utilities
(utilities layer) and any unlayered author css override these
cheaply, and non-Tailwind static consumers override with plain
css. Colors come from tokens or currentColor ONLY — no hardcoded
paint survives a theme flip.
===================================================================== */
@layer components {
/* ---- B0 · the scope root: color-scheme follows the theme classes
the token sheet owns. color-scheme INHERITS — one declaration
themes every native picker, scrollbar and form control in the
subtree: light under :root, dark under .dark (ancestor or self),
forced light under .jx-light. */
:where(.jx-pure):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
/* density adoption (native-contract-fusion Phase 5): the scope
root rides the density interface's text/leading aliases (the
typography LADDER above keeps its fixed steps — declared gap) */
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.6);
}
:where(.dark) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.dark):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
:where(.jx-light) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.jx-light):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
}
/* =====================================================================
B1 · Typography — documented rem steps (the repo ships no
typography size tokens; these literals ARE the scale until a
token ruling lands — do not scatter new sizes elsewhere). The
flow margins are EXPLICIT because preflight zeroes them: a
Tailwind host without this block would render wall-of-text prose.
===================================================================== */
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6):not(.no-jx-pure, .no-jx-pure *) {
margin: 1.5em 0 0.6em;
font-weight: 700;
line-height: 1.25;
color: var(--foreground);
}
:where(.jx-pure) h1:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.875rem;
}
:where(.jx-pure) h2:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.5rem;
}
:where(.jx-pure) h3:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.25rem;
}
:where(.jx-pure) h4:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.125rem;
}
:where(.jx-pure) :where(h5, h6):not(.no-jx-pure, .no-jx-pure *) {
font-size: 1rem;
}
:where(.jx-pure) :where(p, ul, ol, dl, blockquote, pre, table, hr):not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
}
:where(.jx-pure) p:not(.no-jx-pure, .no-jx-pure *) {
line-height: 1.6;
}
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6) :where(p, ul, ol, dl, blockquote, pre, table):first-child:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0;
}
:where(.jx-pure) small:not(.no-jx-pure, .no-jx-pure *) {
font-size: 0.8125rem;
color: var(--muted-foreground);
}
:where(.jx-pure) :where(strong, b):not(.no-jx-pure, .no-jx-pure *) {
font-weight: 700;
}
:where(.jx-pure) blockquote:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-start: 0.875rem;
border-inline-start: 1px solid var(--border);
color: var(--muted-foreground);
}
:where(.jx-pure) :where(code, kbd, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.1em 0.4em;
border: 1px solid var(--border);
background: var(--muted);
font-family: var(--font-mono);
font-size: 0.8125rem;
}
:where(.jx-pure) kbd:not(.no-jx-pure, .no-jx-pure *) {
/* the key cap is ENGRAVED, not lifted (F-2, adversarial-review
2026-09-02 — Owner kbd ruling): --shadow-engrave inset, the
elevation grammar's engrave tier, unified with the registry kbd
component (shadow-engrave). The old `0 1px 0 var(--border)`
lifted-edge dialect is retired — one kbd face across the bare
element and the component. */
box-shadow: var(--shadow-engrave);
}
:where(.jx-pure) pre:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.75rem 1rem;
border: 1px solid var(--border);
background: var(--background);
overflow: auto;
font-family: var(--font-mono);
font-size: 0.8125rem;
line-height: 1.55;
}
/* the code-in-pre lane drops its inline box — the pre owns the box */
:where(.jx-pure) pre :where(code, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0;
border: 0;
background: transparent;
font-size: inherit;
}
:where(.jx-pure) mark:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.05em 0.25em;
background: color-mix(in oklab, var(--secondary) 45%, var(--background));
color: var(--foreground);
}
:where(.jx-pure) hr:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 1.5rem;
border: 0;
border-top: 1px solid var(--border);
}
/* =====================================================================
B2 · Links — the site link law (press-button link variant):
primary text, no underline at rest, underline on hover. Nav links
read as chrome, not prose: foreground at rest, primary + underline
as the hover cue.
===================================================================== */
:where(.jx-pure) a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-underline-offset: 4px;
}
:where(.jx-pure) a:hover:not(.no-jx-pure, .no-jx-pure *) {
text-decoration-line: underline;
}
:where(.jx-pure) nav a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--foreground);
}
:where(.jx-pure) nav a:hover:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-decoration-line: underline;
}
/* =====================================================================
B3 · Buttons — the .jx-press physics restated element-scoped
(hover grows the token shadow + bg-muted; active presses +1px
into the page with the *-press twin — same variable contract,
no WAAPI, no second geometry law). .jx-button is the EXPLICIT
channel for link-look buttons (Codex D2: never auto-style
a[role=button] — CSS cannot add command semantics). Focus is
deliberately NOT set here: the host's focus law owns it (site
base layer paints a/button; static pages keep the UA ring).
===================================================================== */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *) {
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.375rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 1rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
line-height: 1.45;
text-decoration: none;
cursor: pointer;
box-shadow: var(--jx-press-shadow, var(--shadow-xs));
transition:
translate 150ms ease-out,
box-shadow 150ms ease-out,
background-color 150ms ease-out,
border-color 150ms ease-out,
color 150ms ease-out;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):hover:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
box-shadow: var(--jx-press-shadow-hover, var(--shadow-sm));
}
/* :active LAST — at equal specificity the later rule wins the hover pose */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: 1px 1px;
box-shadow: var(--jx-press-shadow-active, var(--shadow-sm-press));
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
cursor: not-allowed;
box-shadow: none;
}
/* =====================================================================
B4+B5 · form controls = @apply applications of the standard
layer (the 13-type allowlist rides each selector; the number lane
keeps the PLATFORM stepper by sharing jx-html-input; checkbox
excludes [role=switch] so the switch gets its own utility) ----- */
/* GENERATED between the markers (css-laws V3): the bare-element
defaults — same declaration source as the .jx-html-* classes,
serialized as element-default rules under :where(.jx-pure) */
/* @jixoai/css-laws:begin:jx-html-face — GENERATED, do not edit (source: packages/css-laws/src/laws) */
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-textarea-min, 5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
height: auto;
resize: vertical;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
--jx-icon-chevron-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
cursor: pointer;
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):disabled, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
@supports not selector(::-moz-range-progress) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
background-image: var(--jx-icon-chevron, var(--jx-icon-chevron-svg));
background-position: right var(--jx-inset, 0.75rem) center;
background-size: var(--jx-icon, 1.25rem);
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
filter: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]) {
min-height: 5.75rem;
padding-block: 0.375rem 0.5rem;
cursor: default;
background-image: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
cursor: pointer;
transition: background-color 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate::before {
opacity: 1;
transform: rotate(0deg);
clip-path: polygon(10% 40%, 10% 60%, 45% 60%, 55% 60%, 90% 60%, 90% 40%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked, :where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate {
background: var(--primary);
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 50%;
background: var(--background);
cursor: pointer;
transition: border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
content: none;
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::after {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
border-radius: 50%;
background: var(--primary);
transform: scale(0);
transition: transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::after {
transform: scale(1);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--background);
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
position: relative;
width: var(--jx-toggle-width, 2.5rem);
height: var(--jx-toggle-track, 1.5rem);
margin: 0;
flex: none;
padding: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
border: 0;
box-shadow: 0 0 0 1px var(--border) inset;
border-radius: calc(infinity * 1px);
background: var(--muted);
cursor: pointer;
transition: background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
inset-block: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inset-inline-start: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inline-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
block-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
border-radius: calc(infinity * 1px);
border: var(--jx-toggle-knob-border, 1px) solid var(--jx-toggle-knob-border-color, var(--primary));
background: var(--background);
transform: translateX(0);
transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1), background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), border-color 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
transform: translateX(calc(var(--jx-toggle-width, 2.5rem) - var(--jx-toggle-track, 1.5rem)));
background: var(--primary-foreground);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
box-shadow: 0 0 0 1px var(--primary) inset;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)) {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch-wrapper {
padding: 0;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-moz-color-swatch {
border: 0;
border-radius: 0;
}
/* @jixoai/css-laws:end:jx-html-face */
/* ---- B6 · label / fieldset / legend (face-owned; not form-
control law — the one-opacity-owner disabled law) -------------
===================================================================== */
:where(.jx-pure) label:not(.no-jx-pure, .no-jx-pure *) {
cursor: pointer;
}
:where(.jx-pure) fieldset:not(.no-jx-pure, .no-jx-pure *) {
min-width: 0;
margin-block: 0.75rem;
padding: 0.875rem 1rem 1rem;
border: 1px solid var(--border);
border-radius: 0;
}
:where(.jx-pure) fieldset:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* ONE opacity owner per subtree (Codex review A3): the group dims to
.5 and the controls inside stay at 1 — two stacked .5 layers
composite to ~.25 and the contrast collapses */
:where(.jx-pure) fieldset:disabled :where(input, textarea, select, button):not(.no-jx-pure, .no-jx-pure *) {
opacity: 1;
cursor: not-allowed;
}
:where(.jx-pure) legend:not(.no-jx-pure, .no-jx-pure *) {
padding-inline: 0.5rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* =====================================================================
B7 · details / summary — document-flow disclosure ONLY (dialog /
popover / tooltip stay Tier-2, Codex D3). Static marker swap, no
open/close animation (progressive enhancement deferred); the
visible focus ring is never replaced by the marker.
===================================================================== */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *) {
display: flex;
align-items: center;
gap: 0.625rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
font-size: 0.875rem;
list-style: none;
cursor: pointer;
transition:
border-color 150ms ease-out,
box-shadow 150ms ease-out;
}
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::-webkit-details-marker {
display: none;
}
/* the marker: a bordered square holding + / − (static swap) */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '+';
box-sizing: border-box;
display: grid;
place-items: center;
width: 1.125rem;
height: 1.125rem;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--muted-foreground);
font-family: var(--font-nav);
font-size: 12px;
line-height: 1;
}
:where(.jx-pure) details[open] > summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '−';
}
:where(.jx-pure) summary:hover:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--primary); /* leans like the checkbox border */
}
:where(.jx-pure) summary:focus-visible:not(.no-jx-pure, .no-jx-pure *) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) details > * + *:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.5rem;
}
/* =====================================================================
B8 · lists / dl — restore the document-flow markers preflight
removes (classless parity) and theme them; nav's link law lives
in B2.
===================================================================== */
:where(.jx-pure) ul:not(.no-jx-pure, .no-jx-pure *) {
list-style: disc;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) ol:not(.no-jx-pure, .no-jx-pure *) {
list-style: decimal;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) li:not(.no-jx-pure, .no-jx-pure *)::marker {
color: var(--muted-foreground);
}
:where(.jx-pure) dl:not(.no-jx-pure, .no-jx-pure *) {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.375rem 1rem;
}
:where(.jx-pure) dt:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
:where(.jx-pure) dd:not(.no-jx-pure, .no-jx-pure *) {
margin: 0;
}
/* =====================================================================
B9 · Tables — the bordered grid law.
===================================================================== */
:where(.jx-pure) table:not(.no-jx-pure, .no-jx-pure *) {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
:where(.jx-pure) caption:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.375rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
caption-side: bottom;
text-align: start;
}
:where(.jx-pure) :where(th, td):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
text-align: start;
}
:where(.jx-pure) th:not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
font-family: var(--font-nav);
font-size: 11px;
font-weight: 400;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
white-space: nowrap;
}
:where(.jx-pure) tbody tr:hover:not(.no-jx-pure, .no-jx-pure *) {
background: color-mix(in oklab, var(--muted) 26%, transparent);
}
/* =====================================================================
B10 · progress / meter / output (Owner completion round, 2026-08-24:
the Codex D6 deferral is overruled — the contracts exist now).
progress: the range-track geometry (8px bordered box, primary
fill); indeterminate trades the fill for a sliding stripe, fully
static under reduced motion. meter: the same box with the
SEMANTIC token mapping — optimum=primary, suboptimal=secondary,
even-less-good=destructive (no hardcoded traffic lights). output:
the mono result lane. Engine pseudos live in SEPARATE rules (the
R1 law: a shared -moz list is dropped whole by Chromium).
===================================================================== */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *) {
display: block;
box-sizing: border-box;
width: 100%;
height: 0.5rem; /* the 8px track family (incl. borders) */
margin: 0;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
appearance: none;
-webkit-appearance: none;
overflow: hidden;
}
:where(.jx-pure) progress:disabled:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* chromium: the track pseudo + the value pseudo */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-bar {
background: var(--background);
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-value {
background: var(--primary);
transition: width 150ms ease-out;
}
/* indeterminate: no percent exists — a muted stripe slides across.
The stripe rides the ELEMENT's own background, never the UA
pseudos: engines reject author paint/animation on progress
pseudos exactly like the number spinners (Codex r4 R4-1 — the
pseudo path compiled but never animated). Part C parks it under
reduced motion. */
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *) {
background:
linear-gradient(in oklab, var(--muted), var(--muted)) 0 0 / 40% 100% no-repeat,
var(--background);
animation: jx-progress-slide 1.2s linear infinite;
}
/* firefox: the element is the track; the bar pseudo is the value */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: var(--primary);
}
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: transparent; /* the element's stripe owns the paint */
}
/* meter: the semantic three-state fill (token-mapped, monochrome law) */
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-bar {
background: var(--background);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-optimum-value {
background: var(--primary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-suboptimum-value {
background: var(--secondary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-even-less-good-value {
background: var(--destructive);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--primary);
}
:where(.jx-pure) meter:-moz-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--secondary);
}
:where(.jx-pure) meter:-moz-sub-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--destructive);
}
/* the stripe keyframes live OUTSIDE the layer's rule bodies… they
are defined once here (keyframes are global; the jx- prefix keeps
the namespace) — declared at the layer's end so both engine rules
above can reference them */
}
@keyframes jx-progress-slide {
from {
background-position: -40% 0, 0 0;
}
to {
background-position: 140% 0, 0 0;
}
}
@layer components {
/* output: the calculation result lane — mono, foreground, inline */
:where(.jx-pure) output:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-mono);
font-size: 0.875rem;
color: var(--foreground);
}
/* =====================================================================
B11 · figure / media — the documentation flow. figure carries the
flow margin + the bordered plate; figcaption rides the caption
law (nav font, small caps, muted, below). Media never overflows
its lane.
===================================================================== */
:where(.jx-pure) :where(img, video):not(.no-jx-pure, .no-jx-pure *) {
max-width: 100%;
height: auto;
}
:where(.jx-pure) figure:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.375rem;
max-width: 100%;
}
:where(.jx-pure) figure > :where(img, video, svg, pre, table):not(.no-jx-pure, .no-jx-pure *) {
border: 1px solid var(--border);
}
:where(.jx-pure) figcaption:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* ---- B13 · switch = @apply application (the ONE input law;
[role=switch] discriminates it from the checkbox) ------------- */
/* the label posture: a wrapping label dims with its input */
:where(.jx-pure) label:has(> input[type='checkbox'][role='switch']):not(.no-jx-pure, .no-jx-pure *) {
display: inline-flex;
align-items: center;
gap: var(--jx-gap, 0.5rem);
cursor: pointer;
user-select: none;
min-block-size: var(--jx-hit, 2.5rem);
&:has(input:disabled) {
cursor: not-allowed;
opacity: 0.5;
}
}
/* =====================================================================
B14 · validation states — the Pico state matrix on the SEMANTIC
palette (openspec D5): aria-invalid='false' leans --success ('✓'
ink + success border + success hover lean); aria-invalid='true'
flips every accent to --error (dashed lanes + '!' ink, checked
fills, the radio DOT, switch track, range fill + thumb).
--destructive is NOT used here — it stays the monochrome
inversion pair for destructive actions. Native :invalid stays
deliberately unhooked (no empty-required surprises).
===================================================================== */
/* lanes: border-color states + the ink glyphs */
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
background-image: var(--jx-icon-invalid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: 2rem;
background-image: var(--jx-icon-valid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
/* checkbox / radio: the checked accent flips to error */
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:indeterminate:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::after {
background: var(--error-foreground);
}
:where(.jx-pure) input[type='checkbox'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success); /* the valid lean */
}
/* switch: the checked track flips */
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::before {
border-color: transparent;
}
/* range: fill + thumb flip */
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
--jx-slider-fill-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-webkit-slider-thumb {
border-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-moz-range-thumb {
background: var(--error);
}
}
/* =====================================================================
B12 · the reverse scope — .no-jx-pure (Owner third revision,
2026-08-24): the r8/r9 `all: revert !important` hatch was too
violent — it also rolled back the HOST's own utilities and inline
styles. Every face rule now carries the exclusion on its subject:
:not(.no-jx-pure, .no-jx-pure *) — an element that IS, or lives
inside, a no-jx-pure subtree never receives the face; everything
the host authored there is untouched. Part A opt-in classes still
work inside islands (author intent, not face paint). INHERITED
properties (color-scheme, custom property tokens) keep flowing
through islands from ancestors — the exclusion is element-level
paint, never a war against the page's theme or the host.
=====================================================================
*/
/* =====================================================================
C · DEGRADATION LAWS — motion and forced colors.
===================================================================== */
/* Reduced motion: FULL STILLNESS, not zero-duration animation (Codex
review B): every Part B transition goes none AND the interactive
displacements (the press translate, the thumb press transform) are
pinned back to their rest poses so nothing ever moves. */
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) :where(textarea, select):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
/* engine pseudos NEVER share a selector list — a non-forgiving list
with an unknown -moz pseudo is dropped WHOLE by Chromium (Codex
r2 R1); one rule per engine surface */
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
/* the indeterminate stripe parks: element animation off (the
authored -moz pseudo animation is likewise killed — one rule per
surface, and the -moz one stands alone) */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *) {
animation: none;
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
animation: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
:where(.jx-pure) input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
transition: none;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: none;
}
}
/* Forced colors (Windows High Contrast & friends): the custom-painted
controls revert to appearance:auto so the SYSTEM palette and glyphs
speak — author paint would flatten into the forced canvas and lose
the checked/unchecked distinction entirely. Box laws (borders,
outlines) survive: forced-colors keeps author borders as system
colors. The opt-in select ALSO drops its gradient chevron or the
restored platform arrow would double up with the leftover paint. */
@media (forced-colors: active) {
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='range']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='color']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select:not(.no-jx-pure, .no-jx-pure *) {
appearance: auto;
-webkit-appearance: auto;
background-image: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before,
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
content: none;
}
}
/* ==== BEGIN GENERATED · jx-auto-dark — scripts/gen-jx-auto-dark.mjs (do not hand-edit) ==== */
/* Derived 1:1 from jixoai.css's .dark block (single source). The gate
rides :where() so the whole variant stays maximally overridable; it
never fires where an explicit .dark already owns the theme, nor
inside .jx-light islands. Mount: <html class="jx-pure jx-auto-dark"> */
@media (prefers-color-scheme: dark) {
:where(.jx-auto-dark):not(.dark, .jx-light *) {
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--terminal: oklch(0.2 0 0);
--terminal-foreground: oklch(1 0 0);
--terminal-hover: color-mix(in oklab, var(--terminal-foreground) 14%, var(--terminal));
--terminal-muted: color-mix(in oklab, var(--terminal-foreground) 8%, var(--terminal));
--card: oklch(0.3211 0 0);
--card-foreground: oklch(1 0 0);
--popover: oklch(0.3211 0 0);
--popover-foreground: oklch(1 0 0);
/* the primary hue drifts -4° toward dark, mirroring the reference */
--primary: oklch(0.7044 0.1872 calc(var(--brand-hue) - 4));
--primary-foreground: oklch(0 0 0);
--primary-text: var(--primary);
--secondary: oklch(0.9691 0.2005 109.6228);
--secondary-foreground: oklch(0 0 0);
--muted: oklch(0.2178 0 0);
--muted-foreground: oklch(0.8452 0 0);
--accent: oklch(0.6755 0.1765 252.2592);
--accent-foreground: oklch(0 0 0);
--destructive: oklch(1 0 0);
--destructive-foreground: oklch(0 0 0);
--border: oklch(1 0 0);
--input: oklch(1 0 0);
--ring: var(--primary);
--success: oklch(0.72 0.16 145);
--success-foreground: oklch(0 0 0);
--warning: oklch(0.78 0.17 85);
--warning-foreground: oklch(0 0 0);
--info: oklch(0.74 0.14 245);
--info-foreground: oklch(0 0 0);
--error: oklch(0.72 0.16 25);
--error-foreground: oklch(0 0 0);
--chart-1: var(--primary);
--chart-2: var(--success);
--chart-3: var(--info);
--chart-4: var(--warning);
--chart-5: var(--error);
--shadow-color: hsl(0 0% 100%);
/* shadow GEOMETRY rides the light baseline rung for rung (Owner ruling,
2026-09-01: sizes must not drift between themes — only the INK
inverts to white; the old 4px-everywhere small rungs were copy-paste
drift, not design) */
--shadow-2xs: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-xs: 2px 2px 0px 0px hsl(0 0% 100% / 0.5);
/* ink compensation (F-11, 2026-09-02): the second layer's alpha is
deliberately NOT mirrored (0.5 light / 1.0 dark) — the black ring
rides directly on the white offset over a black ground, where
half-alpha would read as a gray smear; geometry stays rung for
rung, only the ink density compensates */
--shadow-sm: 2px 2px 0px 0px hsl(0 0% 100% / 1), 1px 1px 0px 1px hsl(0 0% 0% / 1);
--shadow: 4px 4px 0px 0px hsl(0 0% 100% / 1);
--shadow-md: 4px 4px 0px 0px hsl(0 0% 100% / 1), 4px 2px 4px -1px hsl(0 0% 0% / 1);
/* --shadow-lg removed with the light block (F-10) */
/* press poses — same minus-1px law as the light block above */
--shadow-xs-press: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-sm-press: 1px 1px 0px 0px hsl(0 0% 100% / 1), 0px 0px 0px 1px hsl(0 0% 0% / 1);
--shadow-md-press: 3px 3px 0px 0px hsl(0 0% 100% / 1), 3px 1px 4px -1px hsl(0 0% 0% / 1);
/* elevation grammar, dark side: same geometry rung for rung, the
ink inverted to white (the white-shadow law); --shadow-paper is
theme-INDEPENDENT (paper stays white — see the light block).
The engrave duet inverts BOTH inks (the law's mechanical face —
the glow wall's black on dark reads as the carved sheen) */
--jx-engrave-shade: hsl(0 0% 100% / 0.4);
--jx-engrave-glow: hsl(0 0% 0% / 0.96);
--shadow-engrave: inset 1px 1px 0px 0px var(--jx-engrave-shade),
inset -1px -1px 0px 0px var(--jx-engrave-glow);
--shadow-well: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--shadow-well-hover: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.28);
/* floating-surface law, dark side: inverted — scrims and the shadow
layer are semi-transparent WHITE and BRIGHTEN (the white-shadow
law; same 0.32 veil strength as light mode's black) */
--scrim: hsl(0 0% 100% / 0.1);
--surface-shadow: oklch(0 0 0 / 0.32); /* black — r14-17, Owner */
/* ── the surface ladder, dark side (explicit-props §7 / task 1.1):
the M3 dark law — shadows are weak here, the STEPS carry the
hierarchy; the rungs LIGHTEN upward, away from the page void,
and stay below --card (0.3211 — the existing panel tokens keep
their place above the ladder). 减色墨律: role steps, never
overlays. This block feeds the generated prefers-color-scheme
projection in jx-pure.css (gen-jx-auto-dark — single source). */
--surface: var(--background);
--surface-container-lowest: oklch(0.115 0 0);
--surface-container-low: oklch(0.185 0 0);
--surface-container: oklch(0.205 0 0);
--surface-container-high: oklch(0.245 0 0);
--surface-container-highest: oklch(0.29 0 0);
--surface-concave: var(--background);
/* ── the elevation level table, dark side (explicit-props §0.1/§7 /
task 1.2): geometry pinned rung for rung with light (the
2026-09-01 law — sizes never drift between themes), the ink
inverted to white at reduced alpha — the soft-lens compensation
(dark hierarchy rides the LADDER; full-alpha white glow through
a 12px blur would wash it). level-1 keeps the inset duet's
single shade wall at the well-tier strength. */
--jx-elevation-level-1-shadow:
inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--jx-elevation-level-1-surface: var(--surface-concave);
--jx-elevation-level0-shadow: none;
--jx-elevation-level0-surface: var(--surface);
--jx-elevation-level1-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 1px 3px 1px hsl(0 0% 100% / 0.08);
--jx-elevation-level1-surface: var(--surface-container-lowest);
--jx-elevation-level2-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 2px 6px 2px hsl(0 0% 100% / 0.08);
--jx-elevation-level2-surface: var(--surface-container-low);
--jx-elevation-level3-shadow:
0px 1px 3px 0px hsl(0 0% 100% / 0.16),
0px 4px 8px 3px hsl(0 0% 100% / 0.08);
--jx-elevation-level3-surface: var(--surface-container);
--jx-elevation-level4-shadow:
0px 2px 3px 0px hsl(0 0% 100% / 0.16),
0px 6px 10px 4px hsl(0 0% 100% / 0.08);
--jx-elevation-level4-surface: var(--surface-container-high);
--jx-elevation-level5-shadow:
0px 4px 4px 0px hsl(0 0% 100% / 0.16),
0px 8px 12px 6px hsl(0 0% 100% / 0.08);
--jx-elevation-level5-surface: var(--surface-container-highest);
/* the color axis' effective carrier — dark's own --primary (the
hue-drifted one; re-declared per theme scope, the canvas-bug
law) */
--jx-color-effective: var(--primary);
color-scheme: dark;
}
/* the scope-root companion: without it B0's color-scheme: light would
out-shout the inherited root scheme and native pickers/scrollbars
would stay light under dark tokens (the inverted-A2 bug) */
:where(.jx-auto-dark) :where(.jx-pure):not(.jx-light, .jx-light *):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
}
/* ==== END GENERATED · jx-auto-dark ==== */
Chromium is the verified engine of record for v1 — the other columns state the authored law, not a verified build. Every repaint degrades to native paint under forced-colors, so unverified engines never lose the control.
demo
progress · meter · output · figure
The completion round (2026-08-24): progress and meter ride the 8px track family — meter maps its semantics onto tokens (optimum=primary, suboptimal=secondary, even-less-good=destructive; no hardcoded traffic lights), progress's indeterminate state trades the fill for a sliding stripe that parks under reduced motion. output is the mono result lane; figure carries the bordered plate with the caption law below, and media never overflows its lane.
jx-pure · progress · meter · output · figure
The completion round: progress and meter ride the 8px track family (meter maps its semantics onto tokens, no hardcoded traffic lights), the indeterminate state trades the fill for a sliding stripe, output is the mono result lane, and figure carries the bordered plate with the caption law below.
media (img / video) never exceeds its lane; the plate's 1px border is the figure law.
/**
* jx-pure — the face of jixoai-ui (registry/files/theme/jx-pure.css).
*
* V3 (css-laws, 2026-08-28): the native form-control laws are
* SINGLE-SOURCED as typed TS objects in packages/css-laws/src/laws.
* THIS file carries two GENERATED projections of that source (the
* @apply chain is retired — TW4 dev did not reliably emit complex
* utilities onto element selectors):
* Part A slot — the Tier-2 opt-in classes (.jx-control, .jx-slider,
* …), unlayered by design (they beat layered utilities)
* Part B slot — the bare-element defaults under :where(.jx-pure),
* inside this sheet's @layer components
* Regenerate after editing laws: npx tsx packages/css-laws/src/build.ts
* Non-form-control face laws (typography, links, buttons, fieldset,
* details, lists, tables, progress, figure, validation matrix, scope
* law) remain face-authored below.
*
* A · opt-in classes = GENERATED alias slot (css-laws)
* B · element defaults = GENERATED face slot (css-laws) + face-authored laws
* C · degradation laws (face-owned transitions only)
* D · auto-dark (GENERATED by scripts/gen-jx-auto-dark.mjs)
*
* Scope law: .jx-pure is a subtree wrapper — it never reaches into
* shadow roots (CustomElements must @import this sheet inside their
* own shadow style). dialog/popover/tooltip are Tier-2 territory.
*/
/* =====================================================================
A · OPT-IN CLASSES — @apply applications of the standard layer
(the declarations live once in jixoai.css; these selectors only
bind them to the opt-in vocabulary)
===================================================================== */
/* opt-in classes = GENERATED applications of the standard layer
(the declarations live once in packages/css-laws/src/laws; these
selectors bind them to the opt-in vocabulary — Tier-2, unlayered
by design: they beat layered utilities) */
/* @jixoai/css-laws:begin:jx-html-alias — GENERATED, do not edit (source: packages/css-laws/src/laws) */
.jx-slider {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
.jx-slider::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider:dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
.jx-slider[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
.jx-slider:focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
.jx-slider:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-color-swatch {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
.jx-color-swatch::-webkit-color-swatch-wrapper {
padding: 0;
}
.jx-color-swatch::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
.jx-color-swatch::-moz-color-swatch {
border: 0;
border-radius: 0;
}
.jx-tgroup {
corner-shape: var(--corner-shape, bevel);
display: inline-flex;
width: fit-content;
flex-wrap: wrap;
overflow: hidden;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--card);
box-shadow: var(--shadow-2xs);
}
.jx-tgroup> label {
display: inline-flex;
align-items: center;
min-block-size: var(--jx-hit, 2.5rem);
padding-block: calc((var(--jx-hit, 2.5rem) - var(--jx-line, 1.25rem)) / 2);
padding-inline: var(--jx-inset, 0.75rem);
font-family: var(--font-nav);
font-size: var(--jx-text, 0.8125rem);
line-height: var(--jx-line, 1.25rem);
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted-foreground);
background-color: transparent;
border-inline-end: 1px solid var(--border);
cursor: pointer;
user-select: none;
transition: color 150ms ease-out, background-color 150ms ease-out;
}
.jx-tgroup> label:last-child {
border-inline-end: 0;
}
.jx-tgroup> label:not(:has(input:disabled)):hover {
color: var(--foreground);
}
.jx-tgroup> label:has(input:checked) {
background-color: var(--primary);
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:checked):not(:has(input:disabled)):hover {
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-tgroup> label:has(input:disabled) {
cursor: not-allowed;
opacity: 0.45;
}
.jx-tgroup> label > input {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.jx-tgroup[data-chrome='bare'] {
border: 0;
background: transparent;
box-shadow: none;
border-radius: 0;
overflow: visible;
}
.jx-tgroup[data-chrome='bare'] > label {
border-inline-end: 0;
flex: 1 1 auto;
justify-content: center;
}
.jx-tgroup[data-chrome='bare'] > label:not(:has(input:disabled)):hover {
color: var(--foreground);
background-color: color-mix(in oklab, var(--muted) 55%, transparent);
}
@media (prefers-reduced-motion: reduce) {
.jx-tgroup> label {
transition: none;
}
}
.jx-control {
box-sizing: border-box;
display: block;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding: var(--jx-gap, 0.5rem) var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font-size: var(--jx-text, 0.875rem);
color-scheme: light;
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control:focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
.jx-control:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-control[aria-invalid='true'] {
border-style: dashed;
border-color: var(--error);
color: var(--error);
}
.jx-control[aria-invalid='false'] {
border-color: var(--primary);
}
.jx-control::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control[type='email'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
.jx-control {
transition: none;
}
}
.jx-control-shell {
box-sizing: border-box;
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
font-size: var(--jx-text, 0.875rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
box-shadow: var(--shadow-well);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control-shell:has(> .jx-html-clear:last-child) {
padding-inline-end: 0;
}
.jx-control-shell:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control-shell:has(:focus) {
border-color: var(--ring);
}
.jx-control-shell:has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-control-shell:has([aria-invalid='true']), .jx-control-shell.jx-invalid {
border-style: dashed;
}
.jx-control-shell:has(:disabled) {
border-color: var(--muted);
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
.jx-control-shell {
transition: none;
}
}
.jx-control-lane {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
padding: 0;
outline: none;
background: transparent;
color: var(--foreground);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
}
.jx-control-lane::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control-lane::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control-lane[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control-lane[type='email'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
/* @jixoai/css-laws:end:jx-html-alias */
.jx-control-shell.jx-slotted {
padding-inline: var(--jx-inset, 0.75rem);
}
.jx-control-shell .jx-control-lane {
padding-inline: 0;
}
.jx-field {
display: flex;
flex-direction: column;
gap: var(--jx-stack, 0.5rem);
width: 100%;
min-width: 0;
}
.jx-label {
font-family: var(--font-nav);
/* secondary-text is a density ROLE (density-adoption §3): the label
* tracks the ambient scope instead of a fixed 11px (2026-08-29) */
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
cursor: pointer;
}
.jx-error {
display: flex;
align-items: center;
gap: 0.25rem;
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--destructive);
}
.jx-error-mark {
font-weight: bold;
}
/* the shell carries NO chrome itself (final-check ruling): the box
* chrome — border AND fill — lives on a ::before BAND whose height
* matches the -webkit-color-swatch-wrapper (the actual color chip's
* lane). 2026-08-29: the fill moved OFF the shell — an element-painted
* background leaks a full-height rectangle that ears out above/below
* the band on any surface where ambient ≠ --background (cards,
* panels, dark); the band now fills itself.
*
* GEOMETRY LAW (final-check ruling 2, the checkbox/range precedent):
* the chip is a LOCKED size-and-ratio block — height = the hit lane,
* aspect 7:4 (≈4.8rem at the 2.75rem hit — visually balanced, NOT a
* literal width), and the shell is its own SIZE CONTAINER: every
* internal geometry derives from 100cqh, so a density change (or a
* consumer height override) scales the whole chip proportionally —
* the swatch circle, the band, the pill radius, the glyph. The hit
* token sets ONLY the height; nothing else reads it. */
.jx-color-shell {
display: flex;
flex: none;
/* the shell's internal ladder (swatch z1, pipette ::after z2, the
custom-picker overlay z1) is COMPONENT-PRIVATE: container-type
does NOT establish a stacking context (measured, the isolation
clause 2026-09-09), so the shell roots it explicitly — the
deferred class-(a) tail cleared */
isolation: isolate;
/* fit-content protects the ratio-derived width from stretch (grid
tracks, block flow) while aspect-ratio + the locked height keep
it the chip's intrinsic 7:4 */
width: fit-content;
height: var(--jx-hit, 2.5rem);
aspect-ratio: 7 / 4;
container-type: size;
cursor: pointer;
position: relative;
transition: box-shadow 150ms ease-out;
}
.jx-color-shell::before {
content: '';
position: absolute;
inset-inline: 0;
inset-block: calc(100cqh / 6);
border: 1px solid var(--border);
background: var(--background);
pointer-events: none;
corner-left-shape: round;
/* band height = 100cqh − 2×(100cqh/6) = 100cqh × 2/3 — half of it
is the true-semicircle pill radius (no clamp hack) */
border-top-left-radius: calc(100cqh / 3);
border-bottom-left-radius: calc(100cqh / 3);
corner-right-shape: bevel;
/* the right radius rides the SAME cq quantum as the band inset
(100cqh/6 ≈ 8px at the default hit — was var(--radius, 8px),
which froze while every other edge scaled with the container;
B4: no internal dimension outside cq units) */
border-top-right-radius: calc(100cqh / 6);
border-bottom-right-radius: calc(100cqh / 6);
}
.jx-color-expand {
/* both dimensions definite → aspect-ratio yields; the chip keeps
its locked height across the full row.
FLEX PARTICIPATION is re-opened here on purpose: the base shell's
flex:none protects the COMPACT chip, but it also beats any layered
flex utility (this zone is unlayered) — so width:100% alone would
size against the WHOLE flex container and overflow any sibling
(the Tier-1 demo row, 2026-08-29: 77+12+329 > 329). grow reclaims
the full row, shrink shares it; block flow is untouched. */
width: 100%;
flex: 1 1 auto;
}
.jx-color-shell:has([aria-invalid='true'])::before,
.jx-color-shell.jx-invalid::before {
border-style: dashed;
}
.jx-color-shell .jx-color-swatch {
position: relative;
z-index: 1;
flex: none;
/* the chip lane = the container's full height; the swatch circle
inside sizes from the input's own padding (also cqh-relative) */
width: 100cqh;
height: auto;
align-self: stretch;
border: 0;
border-inline-end: 1px solid var(--border);
padding: calc(100cqh / 6);
}
.jx-color-shell .jx-color-swatch:focus-visible {
outline: none;
}
/* clear button: SUPERSEDED by jx-html-clear in the standard layer */
/* @jixoai/css-laws:begin:jx-icon-vocab — GENERATED, do not edit (source: packages/css-laws/src/icon-vocab) */
/* the pipette glyph — an ICON SLOT on the WRAPPER (input[type=color]
* is a replaced element whose ::after is unreliable across engines;
* the label wrapper is non-replaced and paints reliably) */
.jx-color-shell::after {
content: '';
position: absolute;
/* decorative carrier (the law's TRANSIENT INK family) + a ladder
rung — z2 orders against the swatch z1 INSIDE the shell, whose
own isolation: isolate roots the ladder (the isolation clause,
2026-09-09; the shell rule lives in the hand zone above) */
z-index: 2;
/* proportional optics: glyph ≈ 36% of the lane, end inset ≈ 27% —
scale with the container, not with font size */
inset-inline-end: calc(100cqh * 0.27);
top: 50%;
width: calc(100cqh * 0.36);
height: calc(100cqh * 0.36);
translate: 0 -50%;
color: var(--muted-foreground);
background-color: currentColor;
-webkit-mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
pointer-events: none;
}
.jx-color-shell:hover::after {
color: var(--foreground);
}
/* the color-picker chevron — an ICON SLOT (mask, currentColor themes) */
.jx-color-picker-chevron {
display: block;
width: 0.75rem;
height: 0.75rem;
background-color: currentColor;
-webkit-mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
}
/* =====================================================================
Icon vocabulary — the mask/currentColor law. One alpha-only URI per
glyph; the encoded stroke %23000 is an ALPHA SOURCE ONLY. The INK
variants (calendar/clock/valid/invalid) serve UA-shadow pseudos that
reject author mask paint; .dark flips them to %23fff, .jx-light back.
===================================================================== */
@layer theme {
:root {
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* THEME-SCOPED placeholder (canvas bug, Owner 2026-09-04 — same law
as the variant-grammar slots in jixoai.css): custom properties
substitute their var() at the DECLARING element — a :root-only
--jx-placeholder handed every descendant the root's
already-substituted mix, so a scoped .dark/.jx-light
(component-canvas stage, terminal-card, print) flipping
--foreground/--background never re-flipped the placeholder ink
with it. The selector list re-declares the slot ON each theme
scope: one declaration point, zero duplicates */
:root,
.jx-light,
.dark {
--jx-placeholder: color-mix(in oklab, var(--foreground) 40%, var(--background));
}
}
.dark {
/* the author-painted icon set flips to white ink in dark (the
-ink quartet's law extended to the plain slots the input/select
laws consume — black alpha URIs vanish on the dark token sheet) */
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
.jx-light {
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* @jixoai/css-laws:end:jx-icon-vocab */
/* =====================================================================
The zero-class STRUCTURAL input group: a label wrapping a text-like
control AND at least one span composes into the shell — the label
takes the box law, the spans ride as prefix/suffix cells, the
control goes chromeless. NO opt-in class needed.
===================================================================== */
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) {
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
padding-inline: var(--jx-inset, 0.75rem);
cursor: text;
transition: box-shadow 150ms ease-out;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):hover {
box-shadow: var(--shadow-2xs);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > span {
display: inline-flex;
align-items: center;
flex: none;
font-size: var(--jx-text, 0.875rem);
color: var(--muted-foreground);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > input {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
outline: none;
background: transparent;
color: var(--foreground);
font: inherit;
font-size: var(--jx-text, 0.875rem);
padding-inline: 0;
}
/* =====================================================================
Switch size modifiers (face-owned; the standard utility carries the
density-alias default, these opt into explicit sizes)
===================================================================== */
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-sm:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-sm input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 2rem;
--jx-toggle-track: 1.25rem;
--jx-toggle-knob: 0.75rem;
}
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-lg:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-lg input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 3rem;
--jx-toggle-track: 1.5rem;
--jx-toggle-knob: 1.25rem;
}
/* =====================================================================
Bare color input: the locked square standalone (without a .jx-color-
shell wrapper)
===================================================================== */
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: calc(var(--jx-hit, 2.5rem) - 2px);
padding: 2px;
}
/* =====================================================================
Reduced-motion law: the sheet's face-owned transitions neutralize.
===================================================================== */
@media (prefers-reduced-motion: reduce) {
.jx-control,
.jx-control-shell,
.jx-color-shell {
transition: none;
}
}
/* =====================================================================
B · ELEMENT DEFAULTS — the .jx-pure subtree face.
Every rule rides :where(.jx-pure) so the scope class contributes
ZERO specificity inside @layer components: Tailwind utilities
(utilities layer) and any unlayered author css override these
cheaply, and non-Tailwind static consumers override with plain
css. Colors come from tokens or currentColor ONLY — no hardcoded
paint survives a theme flip.
===================================================================== */
@layer components {
/* ---- B0 · the scope root: color-scheme follows the theme classes
the token sheet owns. color-scheme INHERITS — one declaration
themes every native picker, scrollbar and form control in the
subtree: light under :root, dark under .dark (ancestor or self),
forced light under .jx-light. */
:where(.jx-pure):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
/* density adoption (native-contract-fusion Phase 5): the scope
root rides the density interface's text/leading aliases (the
typography LADDER above keeps its fixed steps — declared gap) */
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.6);
}
:where(.dark) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.dark):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
:where(.jx-light) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.jx-light):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
}
/* =====================================================================
B1 · Typography — documented rem steps (the repo ships no
typography size tokens; these literals ARE the scale until a
token ruling lands — do not scatter new sizes elsewhere). The
flow margins are EXPLICIT because preflight zeroes them: a
Tailwind host without this block would render wall-of-text prose.
===================================================================== */
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6):not(.no-jx-pure, .no-jx-pure *) {
margin: 1.5em 0 0.6em;
font-weight: 700;
line-height: 1.25;
color: var(--foreground);
}
:where(.jx-pure) h1:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.875rem;
}
:where(.jx-pure) h2:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.5rem;
}
:where(.jx-pure) h3:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.25rem;
}
:where(.jx-pure) h4:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.125rem;
}
:where(.jx-pure) :where(h5, h6):not(.no-jx-pure, .no-jx-pure *) {
font-size: 1rem;
}
:where(.jx-pure) :where(p, ul, ol, dl, blockquote, pre, table, hr):not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
}
:where(.jx-pure) p:not(.no-jx-pure, .no-jx-pure *) {
line-height: 1.6;
}
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6) :where(p, ul, ol, dl, blockquote, pre, table):first-child:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0;
}
:where(.jx-pure) small:not(.no-jx-pure, .no-jx-pure *) {
font-size: 0.8125rem;
color: var(--muted-foreground);
}
:where(.jx-pure) :where(strong, b):not(.no-jx-pure, .no-jx-pure *) {
font-weight: 700;
}
:where(.jx-pure) blockquote:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-start: 0.875rem;
border-inline-start: 1px solid var(--border);
color: var(--muted-foreground);
}
:where(.jx-pure) :where(code, kbd, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.1em 0.4em;
border: 1px solid var(--border);
background: var(--muted);
font-family: var(--font-mono);
font-size: 0.8125rem;
}
:where(.jx-pure) kbd:not(.no-jx-pure, .no-jx-pure *) {
/* the key cap is ENGRAVED, not lifted (F-2, adversarial-review
2026-09-02 — Owner kbd ruling): --shadow-engrave inset, the
elevation grammar's engrave tier, unified with the registry kbd
component (shadow-engrave). The old `0 1px 0 var(--border)`
lifted-edge dialect is retired — one kbd face across the bare
element and the component. */
box-shadow: var(--shadow-engrave);
}
:where(.jx-pure) pre:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.75rem 1rem;
border: 1px solid var(--border);
background: var(--background);
overflow: auto;
font-family: var(--font-mono);
font-size: 0.8125rem;
line-height: 1.55;
}
/* the code-in-pre lane drops its inline box — the pre owns the box */
:where(.jx-pure) pre :where(code, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0;
border: 0;
background: transparent;
font-size: inherit;
}
:where(.jx-pure) mark:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.05em 0.25em;
background: color-mix(in oklab, var(--secondary) 45%, var(--background));
color: var(--foreground);
}
:where(.jx-pure) hr:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 1.5rem;
border: 0;
border-top: 1px solid var(--border);
}
/* =====================================================================
B2 · Links — the site link law (press-button link variant):
primary text, no underline at rest, underline on hover. Nav links
read as chrome, not prose: foreground at rest, primary + underline
as the hover cue.
===================================================================== */
:where(.jx-pure) a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-underline-offset: 4px;
}
:where(.jx-pure) a:hover:not(.no-jx-pure, .no-jx-pure *) {
text-decoration-line: underline;
}
:where(.jx-pure) nav a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--foreground);
}
:where(.jx-pure) nav a:hover:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-decoration-line: underline;
}
/* =====================================================================
B3 · Buttons — the .jx-press physics restated element-scoped
(hover grows the token shadow + bg-muted; active presses +1px
into the page with the *-press twin — same variable contract,
no WAAPI, no second geometry law). .jx-button is the EXPLICIT
channel for link-look buttons (Codex D2: never auto-style
a[role=button] — CSS cannot add command semantics). Focus is
deliberately NOT set here: the host's focus law owns it (site
base layer paints a/button; static pages keep the UA ring).
===================================================================== */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *) {
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.375rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 1rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
line-height: 1.45;
text-decoration: none;
cursor: pointer;
box-shadow: var(--jx-press-shadow, var(--shadow-xs));
transition:
translate 150ms ease-out,
box-shadow 150ms ease-out,
background-color 150ms ease-out,
border-color 150ms ease-out,
color 150ms ease-out;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):hover:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
box-shadow: var(--jx-press-shadow-hover, var(--shadow-sm));
}
/* :active LAST — at equal specificity the later rule wins the hover pose */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: 1px 1px;
box-shadow: var(--jx-press-shadow-active, var(--shadow-sm-press));
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
cursor: not-allowed;
box-shadow: none;
}
/* =====================================================================
B4+B5 · form controls = @apply applications of the standard
layer (the 13-type allowlist rides each selector; the number lane
keeps the PLATFORM stepper by sharing jx-html-input; checkbox
excludes [role=switch] so the switch gets its own utility) ----- */
/* GENERATED between the markers (css-laws V3): the bare-element
defaults — same declaration source as the .jx-html-* classes,
serialized as element-default rules under :where(.jx-pure) */
/* @jixoai/css-laws:begin:jx-html-face — GENERATED, do not edit (source: packages/css-laws/src/laws) */
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-textarea-min, 5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
height: auto;
resize: vertical;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
--jx-icon-chevron-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
cursor: pointer;
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):disabled, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
@supports not selector(::-moz-range-progress) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
background-image: var(--jx-icon-chevron, var(--jx-icon-chevron-svg));
background-position: right var(--jx-inset, 0.75rem) center;
background-size: var(--jx-icon, 1.25rem);
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
filter: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]) {
min-height: 5.75rem;
padding-block: 0.375rem 0.5rem;
cursor: default;
background-image: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
cursor: pointer;
transition: background-color 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate::before {
opacity: 1;
transform: rotate(0deg);
clip-path: polygon(10% 40%, 10% 60%, 45% 60%, 55% 60%, 90% 60%, 90% 40%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked, :where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate {
background: var(--primary);
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 50%;
background: var(--background);
cursor: pointer;
transition: border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
content: none;
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::after {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
border-radius: 50%;
background: var(--primary);
transform: scale(0);
transition: transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::after {
transform: scale(1);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--background);
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
position: relative;
width: var(--jx-toggle-width, 2.5rem);
height: var(--jx-toggle-track, 1.5rem);
margin: 0;
flex: none;
padding: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
border: 0;
box-shadow: 0 0 0 1px var(--border) inset;
border-radius: calc(infinity * 1px);
background: var(--muted);
cursor: pointer;
transition: background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
inset-block: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inset-inline-start: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inline-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
block-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
border-radius: calc(infinity * 1px);
border: var(--jx-toggle-knob-border, 1px) solid var(--jx-toggle-knob-border-color, var(--primary));
background: var(--background);
transform: translateX(0);
transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1), background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), border-color 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
transform: translateX(calc(var(--jx-toggle-width, 2.5rem) - var(--jx-toggle-track, 1.5rem)));
background: var(--primary-foreground);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
box-shadow: 0 0 0 1px var(--primary) inset;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)) {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch-wrapper {
padding: 0;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-moz-color-swatch {
border: 0;
border-radius: 0;
}
/* @jixoai/css-laws:end:jx-html-face */
/* ---- B6 · label / fieldset / legend (face-owned; not form-
control law — the one-opacity-owner disabled law) -------------
===================================================================== */
:where(.jx-pure) label:not(.no-jx-pure, .no-jx-pure *) {
cursor: pointer;
}
:where(.jx-pure) fieldset:not(.no-jx-pure, .no-jx-pure *) {
min-width: 0;
margin-block: 0.75rem;
padding: 0.875rem 1rem 1rem;
border: 1px solid var(--border);
border-radius: 0;
}
:where(.jx-pure) fieldset:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* ONE opacity owner per subtree (Codex review A3): the group dims to
.5 and the controls inside stay at 1 — two stacked .5 layers
composite to ~.25 and the contrast collapses */
:where(.jx-pure) fieldset:disabled :where(input, textarea, select, button):not(.no-jx-pure, .no-jx-pure *) {
opacity: 1;
cursor: not-allowed;
}
:where(.jx-pure) legend:not(.no-jx-pure, .no-jx-pure *) {
padding-inline: 0.5rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* =====================================================================
B7 · details / summary — document-flow disclosure ONLY (dialog /
popover / tooltip stay Tier-2, Codex D3). Static marker swap, no
open/close animation (progressive enhancement deferred); the
visible focus ring is never replaced by the marker.
===================================================================== */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *) {
display: flex;
align-items: center;
gap: 0.625rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
font-size: 0.875rem;
list-style: none;
cursor: pointer;
transition:
border-color 150ms ease-out,
box-shadow 150ms ease-out;
}
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::-webkit-details-marker {
display: none;
}
/* the marker: a bordered square holding + / − (static swap) */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '+';
box-sizing: border-box;
display: grid;
place-items: center;
width: 1.125rem;
height: 1.125rem;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--muted-foreground);
font-family: var(--font-nav);
font-size: 12px;
line-height: 1;
}
:where(.jx-pure) details[open] > summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '−';
}
:where(.jx-pure) summary:hover:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--primary); /* leans like the checkbox border */
}
:where(.jx-pure) summary:focus-visible:not(.no-jx-pure, .no-jx-pure *) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) details > * + *:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.5rem;
}
/* =====================================================================
B8 · lists / dl — restore the document-flow markers preflight
removes (classless parity) and theme them; nav's link law lives
in B2.
===================================================================== */
:where(.jx-pure) ul:not(.no-jx-pure, .no-jx-pure *) {
list-style: disc;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) ol:not(.no-jx-pure, .no-jx-pure *) {
list-style: decimal;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) li:not(.no-jx-pure, .no-jx-pure *)::marker {
color: var(--muted-foreground);
}
:where(.jx-pure) dl:not(.no-jx-pure, .no-jx-pure *) {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.375rem 1rem;
}
:where(.jx-pure) dt:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
:where(.jx-pure) dd:not(.no-jx-pure, .no-jx-pure *) {
margin: 0;
}
/* =====================================================================
B9 · Tables — the bordered grid law.
===================================================================== */
:where(.jx-pure) table:not(.no-jx-pure, .no-jx-pure *) {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
:where(.jx-pure) caption:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.375rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
caption-side: bottom;
text-align: start;
}
:where(.jx-pure) :where(th, td):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
text-align: start;
}
:where(.jx-pure) th:not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
font-family: var(--font-nav);
font-size: 11px;
font-weight: 400;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
white-space: nowrap;
}
:where(.jx-pure) tbody tr:hover:not(.no-jx-pure, .no-jx-pure *) {
background: color-mix(in oklab, var(--muted) 26%, transparent);
}
/* =====================================================================
B10 · progress / meter / output (Owner completion round, 2026-08-24:
the Codex D6 deferral is overruled — the contracts exist now).
progress: the range-track geometry (8px bordered box, primary
fill); indeterminate trades the fill for a sliding stripe, fully
static under reduced motion. meter: the same box with the
SEMANTIC token mapping — optimum=primary, suboptimal=secondary,
even-less-good=destructive (no hardcoded traffic lights). output:
the mono result lane. Engine pseudos live in SEPARATE rules (the
R1 law: a shared -moz list is dropped whole by Chromium).
===================================================================== */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *) {
display: block;
box-sizing: border-box;
width: 100%;
height: 0.5rem; /* the 8px track family (incl. borders) */
margin: 0;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
appearance: none;
-webkit-appearance: none;
overflow: hidden;
}
:where(.jx-pure) progress:disabled:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* chromium: the track pseudo + the value pseudo */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-bar {
background: var(--background);
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-value {
background: var(--primary);
transition: width 150ms ease-out;
}
/* indeterminate: no percent exists — a muted stripe slides across.
The stripe rides the ELEMENT's own background, never the UA
pseudos: engines reject author paint/animation on progress
pseudos exactly like the number spinners (Codex r4 R4-1 — the
pseudo path compiled but never animated). Part C parks it under
reduced motion. */
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *) {
background:
linear-gradient(in oklab, var(--muted), var(--muted)) 0 0 / 40% 100% no-repeat,
var(--background);
animation: jx-progress-slide 1.2s linear infinite;
}
/* firefox: the element is the track; the bar pseudo is the value */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: var(--primary);
}
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: transparent; /* the element's stripe owns the paint */
}
/* meter: the semantic three-state fill (token-mapped, monochrome law) */
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-bar {
background: var(--background);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-optimum-value {
background: var(--primary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-suboptimum-value {
background: var(--secondary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-even-less-good-value {
background: var(--destructive);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--primary);
}
:where(.jx-pure) meter:-moz-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--secondary);
}
:where(.jx-pure) meter:-moz-sub-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--destructive);
}
/* the stripe keyframes live OUTSIDE the layer's rule bodies… they
are defined once here (keyframes are global; the jx- prefix keeps
the namespace) — declared at the layer's end so both engine rules
above can reference them */
}
@keyframes jx-progress-slide {
from {
background-position: -40% 0, 0 0;
}
to {
background-position: 140% 0, 0 0;
}
}
@layer components {
/* output: the calculation result lane — mono, foreground, inline */
:where(.jx-pure) output:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-mono);
font-size: 0.875rem;
color: var(--foreground);
}
/* =====================================================================
B11 · figure / media — the documentation flow. figure carries the
flow margin + the bordered plate; figcaption rides the caption
law (nav font, small caps, muted, below). Media never overflows
its lane.
===================================================================== */
:where(.jx-pure) :where(img, video):not(.no-jx-pure, .no-jx-pure *) {
max-width: 100%;
height: auto;
}
:where(.jx-pure) figure:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.375rem;
max-width: 100%;
}
:where(.jx-pure) figure > :where(img, video, svg, pre, table):not(.no-jx-pure, .no-jx-pure *) {
border: 1px solid var(--border);
}
:where(.jx-pure) figcaption:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* ---- B13 · switch = @apply application (the ONE input law;
[role=switch] discriminates it from the checkbox) ------------- */
/* the label posture: a wrapping label dims with its input */
:where(.jx-pure) label:has(> input[type='checkbox'][role='switch']):not(.no-jx-pure, .no-jx-pure *) {
display: inline-flex;
align-items: center;
gap: var(--jx-gap, 0.5rem);
cursor: pointer;
user-select: none;
min-block-size: var(--jx-hit, 2.5rem);
&:has(input:disabled) {
cursor: not-allowed;
opacity: 0.5;
}
}
/* =====================================================================
B14 · validation states — the Pico state matrix on the SEMANTIC
palette (openspec D5): aria-invalid='false' leans --success ('✓'
ink + success border + success hover lean); aria-invalid='true'
flips every accent to --error (dashed lanes + '!' ink, checked
fills, the radio DOT, switch track, range fill + thumb).
--destructive is NOT used here — it stays the monochrome
inversion pair for destructive actions. Native :invalid stays
deliberately unhooked (no empty-required surprises).
===================================================================== */
/* lanes: border-color states + the ink glyphs */
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
background-image: var(--jx-icon-invalid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: 2rem;
background-image: var(--jx-icon-valid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
/* checkbox / radio: the checked accent flips to error */
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:indeterminate:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::after {
background: var(--error-foreground);
}
:where(.jx-pure) input[type='checkbox'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success); /* the valid lean */
}
/* switch: the checked track flips */
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::before {
border-color: transparent;
}
/* range: fill + thumb flip */
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
--jx-slider-fill-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-webkit-slider-thumb {
border-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-moz-range-thumb {
background: var(--error);
}
}
/* =====================================================================
B12 · the reverse scope — .no-jx-pure (Owner third revision,
2026-08-24): the r8/r9 `all: revert !important` hatch was too
violent — it also rolled back the HOST's own utilities and inline
styles. Every face rule now carries the exclusion on its subject:
:not(.no-jx-pure, .no-jx-pure *) — an element that IS, or lives
inside, a no-jx-pure subtree never receives the face; everything
the host authored there is untouched. Part A opt-in classes still
work inside islands (author intent, not face paint). INHERITED
properties (color-scheme, custom property tokens) keep flowing
through islands from ancestors — the exclusion is element-level
paint, never a war against the page's theme or the host.
=====================================================================
*/
/* =====================================================================
C · DEGRADATION LAWS — motion and forced colors.
===================================================================== */
/* Reduced motion: FULL STILLNESS, not zero-duration animation (Codex
review B): every Part B transition goes none AND the interactive
displacements (the press translate, the thumb press transform) are
pinned back to their rest poses so nothing ever moves. */
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) :where(textarea, select):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
/* engine pseudos NEVER share a selector list — a non-forgiving list
with an unknown -moz pseudo is dropped WHOLE by Chromium (Codex
r2 R1); one rule per engine surface */
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
/* the indeterminate stripe parks: element animation off (the
authored -moz pseudo animation is likewise killed — one rule per
surface, and the -moz one stands alone) */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *) {
animation: none;
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
animation: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
:where(.jx-pure) input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
transition: none;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: none;
}
}
/* Forced colors (Windows High Contrast & friends): the custom-painted
controls revert to appearance:auto so the SYSTEM palette and glyphs
speak — author paint would flatten into the forced canvas and lose
the checked/unchecked distinction entirely. Box laws (borders,
outlines) survive: forced-colors keeps author borders as system
colors. The opt-in select ALSO drops its gradient chevron or the
restored platform arrow would double up with the leftover paint. */
@media (forced-colors: active) {
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='range']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='color']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select:not(.no-jx-pure, .no-jx-pure *) {
appearance: auto;
-webkit-appearance: auto;
background-image: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before,
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
content: none;
}
}
/* ==== BEGIN GENERATED · jx-auto-dark — scripts/gen-jx-auto-dark.mjs (do not hand-edit) ==== */
/* Derived 1:1 from jixoai.css's .dark block (single source). The gate
rides :where() so the whole variant stays maximally overridable; it
never fires where an explicit .dark already owns the theme, nor
inside .jx-light islands. Mount: <html class="jx-pure jx-auto-dark"> */
@media (prefers-color-scheme: dark) {
:where(.jx-auto-dark):not(.dark, .jx-light *) {
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--terminal: oklch(0.2 0 0);
--terminal-foreground: oklch(1 0 0);
--terminal-hover: color-mix(in oklab, var(--terminal-foreground) 14%, var(--terminal));
--terminal-muted: color-mix(in oklab, var(--terminal-foreground) 8%, var(--terminal));
--card: oklch(0.3211 0 0);
--card-foreground: oklch(1 0 0);
--popover: oklch(0.3211 0 0);
--popover-foreground: oklch(1 0 0);
/* the primary hue drifts -4° toward dark, mirroring the reference */
--primary: oklch(0.7044 0.1872 calc(var(--brand-hue) - 4));
--primary-foreground: oklch(0 0 0);
--primary-text: var(--primary);
--secondary: oklch(0.9691 0.2005 109.6228);
--secondary-foreground: oklch(0 0 0);
--muted: oklch(0.2178 0 0);
--muted-foreground: oklch(0.8452 0 0);
--accent: oklch(0.6755 0.1765 252.2592);
--accent-foreground: oklch(0 0 0);
--destructive: oklch(1 0 0);
--destructive-foreground: oklch(0 0 0);
--border: oklch(1 0 0);
--input: oklch(1 0 0);
--ring: var(--primary);
--success: oklch(0.72 0.16 145);
--success-foreground: oklch(0 0 0);
--warning: oklch(0.78 0.17 85);
--warning-foreground: oklch(0 0 0);
--info: oklch(0.74 0.14 245);
--info-foreground: oklch(0 0 0);
--error: oklch(0.72 0.16 25);
--error-foreground: oklch(0 0 0);
--chart-1: var(--primary);
--chart-2: var(--success);
--chart-3: var(--info);
--chart-4: var(--warning);
--chart-5: var(--error);
--shadow-color: hsl(0 0% 100%);
/* shadow GEOMETRY rides the light baseline rung for rung (Owner ruling,
2026-09-01: sizes must not drift between themes — only the INK
inverts to white; the old 4px-everywhere small rungs were copy-paste
drift, not design) */
--shadow-2xs: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-xs: 2px 2px 0px 0px hsl(0 0% 100% / 0.5);
/* ink compensation (F-11, 2026-09-02): the second layer's alpha is
deliberately NOT mirrored (0.5 light / 1.0 dark) — the black ring
rides directly on the white offset over a black ground, where
half-alpha would read as a gray smear; geometry stays rung for
rung, only the ink density compensates */
--shadow-sm: 2px 2px 0px 0px hsl(0 0% 100% / 1), 1px 1px 0px 1px hsl(0 0% 0% / 1);
--shadow: 4px 4px 0px 0px hsl(0 0% 100% / 1);
--shadow-md: 4px 4px 0px 0px hsl(0 0% 100% / 1), 4px 2px 4px -1px hsl(0 0% 0% / 1);
/* --shadow-lg removed with the light block (F-10) */
/* press poses — same minus-1px law as the light block above */
--shadow-xs-press: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-sm-press: 1px 1px 0px 0px hsl(0 0% 100% / 1), 0px 0px 0px 1px hsl(0 0% 0% / 1);
--shadow-md-press: 3px 3px 0px 0px hsl(0 0% 100% / 1), 3px 1px 4px -1px hsl(0 0% 0% / 1);
/* elevation grammar, dark side: same geometry rung for rung, the
ink inverted to white (the white-shadow law); --shadow-paper is
theme-INDEPENDENT (paper stays white — see the light block).
The engrave duet inverts BOTH inks (the law's mechanical face —
the glow wall's black on dark reads as the carved sheen) */
--jx-engrave-shade: hsl(0 0% 100% / 0.4);
--jx-engrave-glow: hsl(0 0% 0% / 0.96);
--shadow-engrave: inset 1px 1px 0px 0px var(--jx-engrave-shade),
inset -1px -1px 0px 0px var(--jx-engrave-glow);
--shadow-well: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--shadow-well-hover: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.28);
/* floating-surface law, dark side: inverted — scrims and the shadow
layer are semi-transparent WHITE and BRIGHTEN (the white-shadow
law; same 0.32 veil strength as light mode's black) */
--scrim: hsl(0 0% 100% / 0.1);
--surface-shadow: oklch(0 0 0 / 0.32); /* black — r14-17, Owner */
/* ── the surface ladder, dark side (explicit-props §7 / task 1.1):
the M3 dark law — shadows are weak here, the STEPS carry the
hierarchy; the rungs LIGHTEN upward, away from the page void,
and stay below --card (0.3211 — the existing panel tokens keep
their place above the ladder). 减色墨律: role steps, never
overlays. This block feeds the generated prefers-color-scheme
projection in jx-pure.css (gen-jx-auto-dark — single source). */
--surface: var(--background);
--surface-container-lowest: oklch(0.115 0 0);
--surface-container-low: oklch(0.185 0 0);
--surface-container: oklch(0.205 0 0);
--surface-container-high: oklch(0.245 0 0);
--surface-container-highest: oklch(0.29 0 0);
--surface-concave: var(--background);
/* ── the elevation level table, dark side (explicit-props §0.1/§7 /
task 1.2): geometry pinned rung for rung with light (the
2026-09-01 law — sizes never drift between themes), the ink
inverted to white at reduced alpha — the soft-lens compensation
(dark hierarchy rides the LADDER; full-alpha white glow through
a 12px blur would wash it). level-1 keeps the inset duet's
single shade wall at the well-tier strength. */
--jx-elevation-level-1-shadow:
inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--jx-elevation-level-1-surface: var(--surface-concave);
--jx-elevation-level0-shadow: none;
--jx-elevation-level0-surface: var(--surface);
--jx-elevation-level1-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 1px 3px 1px hsl(0 0% 100% / 0.08);
--jx-elevation-level1-surface: var(--surface-container-lowest);
--jx-elevation-level2-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 2px 6px 2px hsl(0 0% 100% / 0.08);
--jx-elevation-level2-surface: var(--surface-container-low);
--jx-elevation-level3-shadow:
0px 1px 3px 0px hsl(0 0% 100% / 0.16),
0px 4px 8px 3px hsl(0 0% 100% / 0.08);
--jx-elevation-level3-surface: var(--surface-container);
--jx-elevation-level4-shadow:
0px 2px 3px 0px hsl(0 0% 100% / 0.16),
0px 6px 10px 4px hsl(0 0% 100% / 0.08);
--jx-elevation-level4-surface: var(--surface-container-high);
--jx-elevation-level5-shadow:
0px 4px 4px 0px hsl(0 0% 100% / 0.16),
0px 8px 12px 6px hsl(0 0% 100% / 0.08);
--jx-elevation-level5-surface: var(--surface-container-highest);
/* the color axis' effective carrier — dark's own --primary (the
hue-drifted one; re-declared per theme scope, the canvas-bug
law) */
--jx-color-effective: var(--primary);
color-scheme: dark;
}
/* the scope-root companion: without it B0's color-scheme: light would
out-shout the inherited root scheme and native pickers/scrollbars
would stay light under dark tokens (the inverted-A2 bug) */
:where(.jx-auto-dark) :where(.jx-pure):not(.jx-light, .jx-light *):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
}
/* ==== END GENERATED · jx-auto-dark ==== */
demo
switch — role=switch on a checkbox
The Pico contract, zero classes: role='switch' on a bare checkbox inside .jx-pure becomes the jixoai switch — square track, square knob with hard on/off contrast (off: muted track + background knob; on: primary track + primary-foreground knob), logical travel (RTL-native), native state/label/FormData untouched. Sizes sm/md/lg (32×20 / 40×24 / 48×28) via the wrapper class or on the input itself.
jx-pure · switch — role=switch on a checkbox
The Pico contract, zero classes: role='switch' on a bare checkbox inside .jx-pure becomes the jixoai switch — square track, square knob with hard on/off contrast, logical travel, native state/label/FormData untouched. Sizes sm/md/lg via the wrapper class or the input itself.
/**
* jx-pure — the face of jixoai-ui (registry/files/theme/jx-pure.css).
*
* V3 (css-laws, 2026-08-28): the native form-control laws are
* SINGLE-SOURCED as typed TS objects in packages/css-laws/src/laws.
* THIS file carries two GENERATED projections of that source (the
* @apply chain is retired — TW4 dev did not reliably emit complex
* utilities onto element selectors):
* Part A slot — the Tier-2 opt-in classes (.jx-control, .jx-slider,
* …), unlayered by design (they beat layered utilities)
* Part B slot — the bare-element defaults under :where(.jx-pure),
* inside this sheet's @layer components
* Regenerate after editing laws: npx tsx packages/css-laws/src/build.ts
* Non-form-control face laws (typography, links, buttons, fieldset,
* details, lists, tables, progress, figure, validation matrix, scope
* law) remain face-authored below.
*
* A · opt-in classes = GENERATED alias slot (css-laws)
* B · element defaults = GENERATED face slot (css-laws) + face-authored laws
* C · degradation laws (face-owned transitions only)
* D · auto-dark (GENERATED by scripts/gen-jx-auto-dark.mjs)
*
* Scope law: .jx-pure is a subtree wrapper — it never reaches into
* shadow roots (CustomElements must @import this sheet inside their
* own shadow style). dialog/popover/tooltip are Tier-2 territory.
*/
/* =====================================================================
A · OPT-IN CLASSES — @apply applications of the standard layer
(the declarations live once in jixoai.css; these selectors only
bind them to the opt-in vocabulary)
===================================================================== */
/* opt-in classes = GENERATED applications of the standard layer
(the declarations live once in packages/css-laws/src/laws; these
selectors bind them to the opt-in vocabulary — Tier-2, unlayered
by design: they beat layered utilities) */
/* @jixoai/css-laws:begin:jx-html-alias — GENERATED, do not edit (source: packages/css-laws/src/laws) */
.jx-slider {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
.jx-slider::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider:dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
.jx-slider[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
.jx-slider:focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
.jx-slider:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-color-swatch {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
.jx-color-swatch::-webkit-color-swatch-wrapper {
padding: 0;
}
.jx-color-swatch::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
.jx-color-swatch::-moz-color-swatch {
border: 0;
border-radius: 0;
}
.jx-tgroup {
corner-shape: var(--corner-shape, bevel);
display: inline-flex;
width: fit-content;
flex-wrap: wrap;
overflow: hidden;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--card);
box-shadow: var(--shadow-2xs);
}
.jx-tgroup> label {
display: inline-flex;
align-items: center;
min-block-size: var(--jx-hit, 2.5rem);
padding-block: calc((var(--jx-hit, 2.5rem) - var(--jx-line, 1.25rem)) / 2);
padding-inline: var(--jx-inset, 0.75rem);
font-family: var(--font-nav);
font-size: var(--jx-text, 0.8125rem);
line-height: var(--jx-line, 1.25rem);
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted-foreground);
background-color: transparent;
border-inline-end: 1px solid var(--border);
cursor: pointer;
user-select: none;
transition: color 150ms ease-out, background-color 150ms ease-out;
}
.jx-tgroup> label:last-child {
border-inline-end: 0;
}
.jx-tgroup> label:not(:has(input:disabled)):hover {
color: var(--foreground);
}
.jx-tgroup> label:has(input:checked) {
background-color: var(--primary);
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:checked):not(:has(input:disabled)):hover {
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-tgroup> label:has(input:disabled) {
cursor: not-allowed;
opacity: 0.45;
}
.jx-tgroup> label > input {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.jx-tgroup[data-chrome='bare'] {
border: 0;
background: transparent;
box-shadow: none;
border-radius: 0;
overflow: visible;
}
.jx-tgroup[data-chrome='bare'] > label {
border-inline-end: 0;
flex: 1 1 auto;
justify-content: center;
}
.jx-tgroup[data-chrome='bare'] > label:not(:has(input:disabled)):hover {
color: var(--foreground);
background-color: color-mix(in oklab, var(--muted) 55%, transparent);
}
@media (prefers-reduced-motion: reduce) {
.jx-tgroup> label {
transition: none;
}
}
.jx-control {
box-sizing: border-box;
display: block;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding: var(--jx-gap, 0.5rem) var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font-size: var(--jx-text, 0.875rem);
color-scheme: light;
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control:focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
.jx-control:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-control[aria-invalid='true'] {
border-style: dashed;
border-color: var(--error);
color: var(--error);
}
.jx-control[aria-invalid='false'] {
border-color: var(--primary);
}
.jx-control::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control[type='email'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
.jx-control {
transition: none;
}
}
.jx-control-shell {
box-sizing: border-box;
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
font-size: var(--jx-text, 0.875rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
box-shadow: var(--shadow-well);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control-shell:has(> .jx-html-clear:last-child) {
padding-inline-end: 0;
}
.jx-control-shell:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control-shell:has(:focus) {
border-color: var(--ring);
}
.jx-control-shell:has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-control-shell:has([aria-invalid='true']), .jx-control-shell.jx-invalid {
border-style: dashed;
}
.jx-control-shell:has(:disabled) {
border-color: var(--muted);
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
.jx-control-shell {
transition: none;
}
}
.jx-control-lane {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
padding: 0;
outline: none;
background: transparent;
color: var(--foreground);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
}
.jx-control-lane::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control-lane::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control-lane[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control-lane[type='email'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
/* @jixoai/css-laws:end:jx-html-alias */
.jx-control-shell.jx-slotted {
padding-inline: var(--jx-inset, 0.75rem);
}
.jx-control-shell .jx-control-lane {
padding-inline: 0;
}
.jx-field {
display: flex;
flex-direction: column;
gap: var(--jx-stack, 0.5rem);
width: 100%;
min-width: 0;
}
.jx-label {
font-family: var(--font-nav);
/* secondary-text is a density ROLE (density-adoption §3): the label
* tracks the ambient scope instead of a fixed 11px (2026-08-29) */
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
cursor: pointer;
}
.jx-error {
display: flex;
align-items: center;
gap: 0.25rem;
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--destructive);
}
.jx-error-mark {
font-weight: bold;
}
/* the shell carries NO chrome itself (final-check ruling): the box
* chrome — border AND fill — lives on a ::before BAND whose height
* matches the -webkit-color-swatch-wrapper (the actual color chip's
* lane). 2026-08-29: the fill moved OFF the shell — an element-painted
* background leaks a full-height rectangle that ears out above/below
* the band on any surface where ambient ≠ --background (cards,
* panels, dark); the band now fills itself.
*
* GEOMETRY LAW (final-check ruling 2, the checkbox/range precedent):
* the chip is a LOCKED size-and-ratio block — height = the hit lane,
* aspect 7:4 (≈4.8rem at the 2.75rem hit — visually balanced, NOT a
* literal width), and the shell is its own SIZE CONTAINER: every
* internal geometry derives from 100cqh, so a density change (or a
* consumer height override) scales the whole chip proportionally —
* the swatch circle, the band, the pill radius, the glyph. The hit
* token sets ONLY the height; nothing else reads it. */
.jx-color-shell {
display: flex;
flex: none;
/* the shell's internal ladder (swatch z1, pipette ::after z2, the
custom-picker overlay z1) is COMPONENT-PRIVATE: container-type
does NOT establish a stacking context (measured, the isolation
clause 2026-09-09), so the shell roots it explicitly — the
deferred class-(a) tail cleared */
isolation: isolate;
/* fit-content protects the ratio-derived width from stretch (grid
tracks, block flow) while aspect-ratio + the locked height keep
it the chip's intrinsic 7:4 */
width: fit-content;
height: var(--jx-hit, 2.5rem);
aspect-ratio: 7 / 4;
container-type: size;
cursor: pointer;
position: relative;
transition: box-shadow 150ms ease-out;
}
.jx-color-shell::before {
content: '';
position: absolute;
inset-inline: 0;
inset-block: calc(100cqh / 6);
border: 1px solid var(--border);
background: var(--background);
pointer-events: none;
corner-left-shape: round;
/* band height = 100cqh − 2×(100cqh/6) = 100cqh × 2/3 — half of it
is the true-semicircle pill radius (no clamp hack) */
border-top-left-radius: calc(100cqh / 3);
border-bottom-left-radius: calc(100cqh / 3);
corner-right-shape: bevel;
/* the right radius rides the SAME cq quantum as the band inset
(100cqh/6 ≈ 8px at the default hit — was var(--radius, 8px),
which froze while every other edge scaled with the container;
B4: no internal dimension outside cq units) */
border-top-right-radius: calc(100cqh / 6);
border-bottom-right-radius: calc(100cqh / 6);
}
.jx-color-expand {
/* both dimensions definite → aspect-ratio yields; the chip keeps
its locked height across the full row.
FLEX PARTICIPATION is re-opened here on purpose: the base shell's
flex:none protects the COMPACT chip, but it also beats any layered
flex utility (this zone is unlayered) — so width:100% alone would
size against the WHOLE flex container and overflow any sibling
(the Tier-1 demo row, 2026-08-29: 77+12+329 > 329). grow reclaims
the full row, shrink shares it; block flow is untouched. */
width: 100%;
flex: 1 1 auto;
}
.jx-color-shell:has([aria-invalid='true'])::before,
.jx-color-shell.jx-invalid::before {
border-style: dashed;
}
.jx-color-shell .jx-color-swatch {
position: relative;
z-index: 1;
flex: none;
/* the chip lane = the container's full height; the swatch circle
inside sizes from the input's own padding (also cqh-relative) */
width: 100cqh;
height: auto;
align-self: stretch;
border: 0;
border-inline-end: 1px solid var(--border);
padding: calc(100cqh / 6);
}
.jx-color-shell .jx-color-swatch:focus-visible {
outline: none;
}
/* clear button: SUPERSEDED by jx-html-clear in the standard layer */
/* @jixoai/css-laws:begin:jx-icon-vocab — GENERATED, do not edit (source: packages/css-laws/src/icon-vocab) */
/* the pipette glyph — an ICON SLOT on the WRAPPER (input[type=color]
* is a replaced element whose ::after is unreliable across engines;
* the label wrapper is non-replaced and paints reliably) */
.jx-color-shell::after {
content: '';
position: absolute;
/* decorative carrier (the law's TRANSIENT INK family) + a ladder
rung — z2 orders against the swatch z1 INSIDE the shell, whose
own isolation: isolate roots the ladder (the isolation clause,
2026-09-09; the shell rule lives in the hand zone above) */
z-index: 2;
/* proportional optics: glyph ≈ 36% of the lane, end inset ≈ 27% —
scale with the container, not with font size */
inset-inline-end: calc(100cqh * 0.27);
top: 50%;
width: calc(100cqh * 0.36);
height: calc(100cqh * 0.36);
translate: 0 -50%;
color: var(--muted-foreground);
background-color: currentColor;
-webkit-mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
pointer-events: none;
}
.jx-color-shell:hover::after {
color: var(--foreground);
}
/* the color-picker chevron — an ICON SLOT (mask, currentColor themes) */
.jx-color-picker-chevron {
display: block;
width: 0.75rem;
height: 0.75rem;
background-color: currentColor;
-webkit-mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
}
/* =====================================================================
Icon vocabulary — the mask/currentColor law. One alpha-only URI per
glyph; the encoded stroke %23000 is an ALPHA SOURCE ONLY. The INK
variants (calendar/clock/valid/invalid) serve UA-shadow pseudos that
reject author mask paint; .dark flips them to %23fff, .jx-light back.
===================================================================== */
@layer theme {
:root {
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* THEME-SCOPED placeholder (canvas bug, Owner 2026-09-04 — same law
as the variant-grammar slots in jixoai.css): custom properties
substitute their var() at the DECLARING element — a :root-only
--jx-placeholder handed every descendant the root's
already-substituted mix, so a scoped .dark/.jx-light
(component-canvas stage, terminal-card, print) flipping
--foreground/--background never re-flipped the placeholder ink
with it. The selector list re-declares the slot ON each theme
scope: one declaration point, zero duplicates */
:root,
.jx-light,
.dark {
--jx-placeholder: color-mix(in oklab, var(--foreground) 40%, var(--background));
}
}
.dark {
/* the author-painted icon set flips to white ink in dark (the
-ink quartet's law extended to the plain slots the input/select
laws consume — black alpha URIs vanish on the dark token sheet) */
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
.jx-light {
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* @jixoai/css-laws:end:jx-icon-vocab */
/* =====================================================================
The zero-class STRUCTURAL input group: a label wrapping a text-like
control AND at least one span composes into the shell — the label
takes the box law, the spans ride as prefix/suffix cells, the
control goes chromeless. NO opt-in class needed.
===================================================================== */
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) {
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
padding-inline: var(--jx-inset, 0.75rem);
cursor: text;
transition: box-shadow 150ms ease-out;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):hover {
box-shadow: var(--shadow-2xs);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > span {
display: inline-flex;
align-items: center;
flex: none;
font-size: var(--jx-text, 0.875rem);
color: var(--muted-foreground);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > input {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
outline: none;
background: transparent;
color: var(--foreground);
font: inherit;
font-size: var(--jx-text, 0.875rem);
padding-inline: 0;
}
/* =====================================================================
Switch size modifiers (face-owned; the standard utility carries the
density-alias default, these opt into explicit sizes)
===================================================================== */
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-sm:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-sm input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 2rem;
--jx-toggle-track: 1.25rem;
--jx-toggle-knob: 0.75rem;
}
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-lg:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-lg input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 3rem;
--jx-toggle-track: 1.5rem;
--jx-toggle-knob: 1.25rem;
}
/* =====================================================================
Bare color input: the locked square standalone (without a .jx-color-
shell wrapper)
===================================================================== */
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: calc(var(--jx-hit, 2.5rem) - 2px);
padding: 2px;
}
/* =====================================================================
Reduced-motion law: the sheet's face-owned transitions neutralize.
===================================================================== */
@media (prefers-reduced-motion: reduce) {
.jx-control,
.jx-control-shell,
.jx-color-shell {
transition: none;
}
}
/* =====================================================================
B · ELEMENT DEFAULTS — the .jx-pure subtree face.
Every rule rides :where(.jx-pure) so the scope class contributes
ZERO specificity inside @layer components: Tailwind utilities
(utilities layer) and any unlayered author css override these
cheaply, and non-Tailwind static consumers override with plain
css. Colors come from tokens or currentColor ONLY — no hardcoded
paint survives a theme flip.
===================================================================== */
@layer components {
/* ---- B0 · the scope root: color-scheme follows the theme classes
the token sheet owns. color-scheme INHERITS — one declaration
themes every native picker, scrollbar and form control in the
subtree: light under :root, dark under .dark (ancestor or self),
forced light under .jx-light. */
:where(.jx-pure):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
/* density adoption (native-contract-fusion Phase 5): the scope
root rides the density interface's text/leading aliases (the
typography LADDER above keeps its fixed steps — declared gap) */
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.6);
}
:where(.dark) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.dark):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
:where(.jx-light) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.jx-light):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
}
/* =====================================================================
B1 · Typography — documented rem steps (the repo ships no
typography size tokens; these literals ARE the scale until a
token ruling lands — do not scatter new sizes elsewhere). The
flow margins are EXPLICIT because preflight zeroes them: a
Tailwind host without this block would render wall-of-text prose.
===================================================================== */
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6):not(.no-jx-pure, .no-jx-pure *) {
margin: 1.5em 0 0.6em;
font-weight: 700;
line-height: 1.25;
color: var(--foreground);
}
:where(.jx-pure) h1:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.875rem;
}
:where(.jx-pure) h2:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.5rem;
}
:where(.jx-pure) h3:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.25rem;
}
:where(.jx-pure) h4:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.125rem;
}
:where(.jx-pure) :where(h5, h6):not(.no-jx-pure, .no-jx-pure *) {
font-size: 1rem;
}
:where(.jx-pure) :where(p, ul, ol, dl, blockquote, pre, table, hr):not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
}
:where(.jx-pure) p:not(.no-jx-pure, .no-jx-pure *) {
line-height: 1.6;
}
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6) :where(p, ul, ol, dl, blockquote, pre, table):first-child:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0;
}
:where(.jx-pure) small:not(.no-jx-pure, .no-jx-pure *) {
font-size: 0.8125rem;
color: var(--muted-foreground);
}
:where(.jx-pure) :where(strong, b):not(.no-jx-pure, .no-jx-pure *) {
font-weight: 700;
}
:where(.jx-pure) blockquote:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-start: 0.875rem;
border-inline-start: 1px solid var(--border);
color: var(--muted-foreground);
}
:where(.jx-pure) :where(code, kbd, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.1em 0.4em;
border: 1px solid var(--border);
background: var(--muted);
font-family: var(--font-mono);
font-size: 0.8125rem;
}
:where(.jx-pure) kbd:not(.no-jx-pure, .no-jx-pure *) {
/* the key cap is ENGRAVED, not lifted (F-2, adversarial-review
2026-09-02 — Owner kbd ruling): --shadow-engrave inset, the
elevation grammar's engrave tier, unified with the registry kbd
component (shadow-engrave). The old `0 1px 0 var(--border)`
lifted-edge dialect is retired — one kbd face across the bare
element and the component. */
box-shadow: var(--shadow-engrave);
}
:where(.jx-pure) pre:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.75rem 1rem;
border: 1px solid var(--border);
background: var(--background);
overflow: auto;
font-family: var(--font-mono);
font-size: 0.8125rem;
line-height: 1.55;
}
/* the code-in-pre lane drops its inline box — the pre owns the box */
:where(.jx-pure) pre :where(code, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0;
border: 0;
background: transparent;
font-size: inherit;
}
:where(.jx-pure) mark:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.05em 0.25em;
background: color-mix(in oklab, var(--secondary) 45%, var(--background));
color: var(--foreground);
}
:where(.jx-pure) hr:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 1.5rem;
border: 0;
border-top: 1px solid var(--border);
}
/* =====================================================================
B2 · Links — the site link law (press-button link variant):
primary text, no underline at rest, underline on hover. Nav links
read as chrome, not prose: foreground at rest, primary + underline
as the hover cue.
===================================================================== */
:where(.jx-pure) a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-underline-offset: 4px;
}
:where(.jx-pure) a:hover:not(.no-jx-pure, .no-jx-pure *) {
text-decoration-line: underline;
}
:where(.jx-pure) nav a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--foreground);
}
:where(.jx-pure) nav a:hover:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-decoration-line: underline;
}
/* =====================================================================
B3 · Buttons — the .jx-press physics restated element-scoped
(hover grows the token shadow + bg-muted; active presses +1px
into the page with the *-press twin — same variable contract,
no WAAPI, no second geometry law). .jx-button is the EXPLICIT
channel for link-look buttons (Codex D2: never auto-style
a[role=button] — CSS cannot add command semantics). Focus is
deliberately NOT set here: the host's focus law owns it (site
base layer paints a/button; static pages keep the UA ring).
===================================================================== */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *) {
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.375rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 1rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
line-height: 1.45;
text-decoration: none;
cursor: pointer;
box-shadow: var(--jx-press-shadow, var(--shadow-xs));
transition:
translate 150ms ease-out,
box-shadow 150ms ease-out,
background-color 150ms ease-out,
border-color 150ms ease-out,
color 150ms ease-out;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):hover:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
box-shadow: var(--jx-press-shadow-hover, var(--shadow-sm));
}
/* :active LAST — at equal specificity the later rule wins the hover pose */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: 1px 1px;
box-shadow: var(--jx-press-shadow-active, var(--shadow-sm-press));
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
cursor: not-allowed;
box-shadow: none;
}
/* =====================================================================
B4+B5 · form controls = @apply applications of the standard
layer (the 13-type allowlist rides each selector; the number lane
keeps the PLATFORM stepper by sharing jx-html-input; checkbox
excludes [role=switch] so the switch gets its own utility) ----- */
/* GENERATED between the markers (css-laws V3): the bare-element
defaults — same declaration source as the .jx-html-* classes,
serialized as element-default rules under :where(.jx-pure) */
/* @jixoai/css-laws:begin:jx-html-face — GENERATED, do not edit (source: packages/css-laws/src/laws) */
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-textarea-min, 5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
height: auto;
resize: vertical;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
--jx-icon-chevron-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
cursor: pointer;
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):disabled, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
@supports not selector(::-moz-range-progress) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
background-image: var(--jx-icon-chevron, var(--jx-icon-chevron-svg));
background-position: right var(--jx-inset, 0.75rem) center;
background-size: var(--jx-icon, 1.25rem);
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
filter: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]) {
min-height: 5.75rem;
padding-block: 0.375rem 0.5rem;
cursor: default;
background-image: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
cursor: pointer;
transition: background-color 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate::before {
opacity: 1;
transform: rotate(0deg);
clip-path: polygon(10% 40%, 10% 60%, 45% 60%, 55% 60%, 90% 60%, 90% 40%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked, :where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate {
background: var(--primary);
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 50%;
background: var(--background);
cursor: pointer;
transition: border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
content: none;
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::after {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
border-radius: 50%;
background: var(--primary);
transform: scale(0);
transition: transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::after {
transform: scale(1);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--background);
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
position: relative;
width: var(--jx-toggle-width, 2.5rem);
height: var(--jx-toggle-track, 1.5rem);
margin: 0;
flex: none;
padding: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
border: 0;
box-shadow: 0 0 0 1px var(--border) inset;
border-radius: calc(infinity * 1px);
background: var(--muted);
cursor: pointer;
transition: background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
inset-block: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inset-inline-start: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inline-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
block-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
border-radius: calc(infinity * 1px);
border: var(--jx-toggle-knob-border, 1px) solid var(--jx-toggle-knob-border-color, var(--primary));
background: var(--background);
transform: translateX(0);
transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1), background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), border-color 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
transform: translateX(calc(var(--jx-toggle-width, 2.5rem) - var(--jx-toggle-track, 1.5rem)));
background: var(--primary-foreground);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
box-shadow: 0 0 0 1px var(--primary) inset;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)) {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch-wrapper {
padding: 0;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-moz-color-swatch {
border: 0;
border-radius: 0;
}
/* @jixoai/css-laws:end:jx-html-face */
/* ---- B6 · label / fieldset / legend (face-owned; not form-
control law — the one-opacity-owner disabled law) -------------
===================================================================== */
:where(.jx-pure) label:not(.no-jx-pure, .no-jx-pure *) {
cursor: pointer;
}
:where(.jx-pure) fieldset:not(.no-jx-pure, .no-jx-pure *) {
min-width: 0;
margin-block: 0.75rem;
padding: 0.875rem 1rem 1rem;
border: 1px solid var(--border);
border-radius: 0;
}
:where(.jx-pure) fieldset:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* ONE opacity owner per subtree (Codex review A3): the group dims to
.5 and the controls inside stay at 1 — two stacked .5 layers
composite to ~.25 and the contrast collapses */
:where(.jx-pure) fieldset:disabled :where(input, textarea, select, button):not(.no-jx-pure, .no-jx-pure *) {
opacity: 1;
cursor: not-allowed;
}
:where(.jx-pure) legend:not(.no-jx-pure, .no-jx-pure *) {
padding-inline: 0.5rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* =====================================================================
B7 · details / summary — document-flow disclosure ONLY (dialog /
popover / tooltip stay Tier-2, Codex D3). Static marker swap, no
open/close animation (progressive enhancement deferred); the
visible focus ring is never replaced by the marker.
===================================================================== */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *) {
display: flex;
align-items: center;
gap: 0.625rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
font-size: 0.875rem;
list-style: none;
cursor: pointer;
transition:
border-color 150ms ease-out,
box-shadow 150ms ease-out;
}
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::-webkit-details-marker {
display: none;
}
/* the marker: a bordered square holding + / − (static swap) */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '+';
box-sizing: border-box;
display: grid;
place-items: center;
width: 1.125rem;
height: 1.125rem;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--muted-foreground);
font-family: var(--font-nav);
font-size: 12px;
line-height: 1;
}
:where(.jx-pure) details[open] > summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '−';
}
:where(.jx-pure) summary:hover:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--primary); /* leans like the checkbox border */
}
:where(.jx-pure) summary:focus-visible:not(.no-jx-pure, .no-jx-pure *) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) details > * + *:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.5rem;
}
/* =====================================================================
B8 · lists / dl — restore the document-flow markers preflight
removes (classless parity) and theme them; nav's link law lives
in B2.
===================================================================== */
:where(.jx-pure) ul:not(.no-jx-pure, .no-jx-pure *) {
list-style: disc;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) ol:not(.no-jx-pure, .no-jx-pure *) {
list-style: decimal;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) li:not(.no-jx-pure, .no-jx-pure *)::marker {
color: var(--muted-foreground);
}
:where(.jx-pure) dl:not(.no-jx-pure, .no-jx-pure *) {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.375rem 1rem;
}
:where(.jx-pure) dt:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
:where(.jx-pure) dd:not(.no-jx-pure, .no-jx-pure *) {
margin: 0;
}
/* =====================================================================
B9 · Tables — the bordered grid law.
===================================================================== */
:where(.jx-pure) table:not(.no-jx-pure, .no-jx-pure *) {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
:where(.jx-pure) caption:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.375rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
caption-side: bottom;
text-align: start;
}
:where(.jx-pure) :where(th, td):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
text-align: start;
}
:where(.jx-pure) th:not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
font-family: var(--font-nav);
font-size: 11px;
font-weight: 400;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
white-space: nowrap;
}
:where(.jx-pure) tbody tr:hover:not(.no-jx-pure, .no-jx-pure *) {
background: color-mix(in oklab, var(--muted) 26%, transparent);
}
/* =====================================================================
B10 · progress / meter / output (Owner completion round, 2026-08-24:
the Codex D6 deferral is overruled — the contracts exist now).
progress: the range-track geometry (8px bordered box, primary
fill); indeterminate trades the fill for a sliding stripe, fully
static under reduced motion. meter: the same box with the
SEMANTIC token mapping — optimum=primary, suboptimal=secondary,
even-less-good=destructive (no hardcoded traffic lights). output:
the mono result lane. Engine pseudos live in SEPARATE rules (the
R1 law: a shared -moz list is dropped whole by Chromium).
===================================================================== */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *) {
display: block;
box-sizing: border-box;
width: 100%;
height: 0.5rem; /* the 8px track family (incl. borders) */
margin: 0;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
appearance: none;
-webkit-appearance: none;
overflow: hidden;
}
:where(.jx-pure) progress:disabled:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* chromium: the track pseudo + the value pseudo */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-bar {
background: var(--background);
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-value {
background: var(--primary);
transition: width 150ms ease-out;
}
/* indeterminate: no percent exists — a muted stripe slides across.
The stripe rides the ELEMENT's own background, never the UA
pseudos: engines reject author paint/animation on progress
pseudos exactly like the number spinners (Codex r4 R4-1 — the
pseudo path compiled but never animated). Part C parks it under
reduced motion. */
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *) {
background:
linear-gradient(in oklab, var(--muted), var(--muted)) 0 0 / 40% 100% no-repeat,
var(--background);
animation: jx-progress-slide 1.2s linear infinite;
}
/* firefox: the element is the track; the bar pseudo is the value */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: var(--primary);
}
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: transparent; /* the element's stripe owns the paint */
}
/* meter: the semantic three-state fill (token-mapped, monochrome law) */
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-bar {
background: var(--background);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-optimum-value {
background: var(--primary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-suboptimum-value {
background: var(--secondary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-even-less-good-value {
background: var(--destructive);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--primary);
}
:where(.jx-pure) meter:-moz-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--secondary);
}
:where(.jx-pure) meter:-moz-sub-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--destructive);
}
/* the stripe keyframes live OUTSIDE the layer's rule bodies… they
are defined once here (keyframes are global; the jx- prefix keeps
the namespace) — declared at the layer's end so both engine rules
above can reference them */
}
@keyframes jx-progress-slide {
from {
background-position: -40% 0, 0 0;
}
to {
background-position: 140% 0, 0 0;
}
}
@layer components {
/* output: the calculation result lane — mono, foreground, inline */
:where(.jx-pure) output:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-mono);
font-size: 0.875rem;
color: var(--foreground);
}
/* =====================================================================
B11 · figure / media — the documentation flow. figure carries the
flow margin + the bordered plate; figcaption rides the caption
law (nav font, small caps, muted, below). Media never overflows
its lane.
===================================================================== */
:where(.jx-pure) :where(img, video):not(.no-jx-pure, .no-jx-pure *) {
max-width: 100%;
height: auto;
}
:where(.jx-pure) figure:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.375rem;
max-width: 100%;
}
:where(.jx-pure) figure > :where(img, video, svg, pre, table):not(.no-jx-pure, .no-jx-pure *) {
border: 1px solid var(--border);
}
:where(.jx-pure) figcaption:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* ---- B13 · switch = @apply application (the ONE input law;
[role=switch] discriminates it from the checkbox) ------------- */
/* the label posture: a wrapping label dims with its input */
:where(.jx-pure) label:has(> input[type='checkbox'][role='switch']):not(.no-jx-pure, .no-jx-pure *) {
display: inline-flex;
align-items: center;
gap: var(--jx-gap, 0.5rem);
cursor: pointer;
user-select: none;
min-block-size: var(--jx-hit, 2.5rem);
&:has(input:disabled) {
cursor: not-allowed;
opacity: 0.5;
}
}
/* =====================================================================
B14 · validation states — the Pico state matrix on the SEMANTIC
palette (openspec D5): aria-invalid='false' leans --success ('✓'
ink + success border + success hover lean); aria-invalid='true'
flips every accent to --error (dashed lanes + '!' ink, checked
fills, the radio DOT, switch track, range fill + thumb).
--destructive is NOT used here — it stays the monochrome
inversion pair for destructive actions. Native :invalid stays
deliberately unhooked (no empty-required surprises).
===================================================================== */
/* lanes: border-color states + the ink glyphs */
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
background-image: var(--jx-icon-invalid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: 2rem;
background-image: var(--jx-icon-valid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
/* checkbox / radio: the checked accent flips to error */
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:indeterminate:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::after {
background: var(--error-foreground);
}
:where(.jx-pure) input[type='checkbox'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success); /* the valid lean */
}
/* switch: the checked track flips */
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::before {
border-color: transparent;
}
/* range: fill + thumb flip */
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
--jx-slider-fill-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-webkit-slider-thumb {
border-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-moz-range-thumb {
background: var(--error);
}
}
/* =====================================================================
B12 · the reverse scope — .no-jx-pure (Owner third revision,
2026-08-24): the r8/r9 `all: revert !important` hatch was too
violent — it also rolled back the HOST's own utilities and inline
styles. Every face rule now carries the exclusion on its subject:
:not(.no-jx-pure, .no-jx-pure *) — an element that IS, or lives
inside, a no-jx-pure subtree never receives the face; everything
the host authored there is untouched. Part A opt-in classes still
work inside islands (author intent, not face paint). INHERITED
properties (color-scheme, custom property tokens) keep flowing
through islands from ancestors — the exclusion is element-level
paint, never a war against the page's theme or the host.
=====================================================================
*/
/* =====================================================================
C · DEGRADATION LAWS — motion and forced colors.
===================================================================== */
/* Reduced motion: FULL STILLNESS, not zero-duration animation (Codex
review B): every Part B transition goes none AND the interactive
displacements (the press translate, the thumb press transform) are
pinned back to their rest poses so nothing ever moves. */
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) :where(textarea, select):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
/* engine pseudos NEVER share a selector list — a non-forgiving list
with an unknown -moz pseudo is dropped WHOLE by Chromium (Codex
r2 R1); one rule per engine surface */
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
/* the indeterminate stripe parks: element animation off (the
authored -moz pseudo animation is likewise killed — one rule per
surface, and the -moz one stands alone) */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *) {
animation: none;
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
animation: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
:where(.jx-pure) input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
transition: none;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: none;
}
}
/* Forced colors (Windows High Contrast & friends): the custom-painted
controls revert to appearance:auto so the SYSTEM palette and glyphs
speak — author paint would flatten into the forced canvas and lose
the checked/unchecked distinction entirely. Box laws (borders,
outlines) survive: forced-colors keeps author borders as system
colors. The opt-in select ALSO drops its gradient chevron or the
restored platform arrow would double up with the leftover paint. */
@media (forced-colors: active) {
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='range']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='color']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select:not(.no-jx-pure, .no-jx-pure *) {
appearance: auto;
-webkit-appearance: auto;
background-image: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before,
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
content: none;
}
}
/* ==== BEGIN GENERATED · jx-auto-dark — scripts/gen-jx-auto-dark.mjs (do not hand-edit) ==== */
/* Derived 1:1 from jixoai.css's .dark block (single source). The gate
rides :where() so the whole variant stays maximally overridable; it
never fires where an explicit .dark already owns the theme, nor
inside .jx-light islands. Mount: <html class="jx-pure jx-auto-dark"> */
@media (prefers-color-scheme: dark) {
:where(.jx-auto-dark):not(.dark, .jx-light *) {
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--terminal: oklch(0.2 0 0);
--terminal-foreground: oklch(1 0 0);
--terminal-hover: color-mix(in oklab, var(--terminal-foreground) 14%, var(--terminal));
--terminal-muted: color-mix(in oklab, var(--terminal-foreground) 8%, var(--terminal));
--card: oklch(0.3211 0 0);
--card-foreground: oklch(1 0 0);
--popover: oklch(0.3211 0 0);
--popover-foreground: oklch(1 0 0);
/* the primary hue drifts -4° toward dark, mirroring the reference */
--primary: oklch(0.7044 0.1872 calc(var(--brand-hue) - 4));
--primary-foreground: oklch(0 0 0);
--primary-text: var(--primary);
--secondary: oklch(0.9691 0.2005 109.6228);
--secondary-foreground: oklch(0 0 0);
--muted: oklch(0.2178 0 0);
--muted-foreground: oklch(0.8452 0 0);
--accent: oklch(0.6755 0.1765 252.2592);
--accent-foreground: oklch(0 0 0);
--destructive: oklch(1 0 0);
--destructive-foreground: oklch(0 0 0);
--border: oklch(1 0 0);
--input: oklch(1 0 0);
--ring: var(--primary);
--success: oklch(0.72 0.16 145);
--success-foreground: oklch(0 0 0);
--warning: oklch(0.78 0.17 85);
--warning-foreground: oklch(0 0 0);
--info: oklch(0.74 0.14 245);
--info-foreground: oklch(0 0 0);
--error: oklch(0.72 0.16 25);
--error-foreground: oklch(0 0 0);
--chart-1: var(--primary);
--chart-2: var(--success);
--chart-3: var(--info);
--chart-4: var(--warning);
--chart-5: var(--error);
--shadow-color: hsl(0 0% 100%);
/* shadow GEOMETRY rides the light baseline rung for rung (Owner ruling,
2026-09-01: sizes must not drift between themes — only the INK
inverts to white; the old 4px-everywhere small rungs were copy-paste
drift, not design) */
--shadow-2xs: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-xs: 2px 2px 0px 0px hsl(0 0% 100% / 0.5);
/* ink compensation (F-11, 2026-09-02): the second layer's alpha is
deliberately NOT mirrored (0.5 light / 1.0 dark) — the black ring
rides directly on the white offset over a black ground, where
half-alpha would read as a gray smear; geometry stays rung for
rung, only the ink density compensates */
--shadow-sm: 2px 2px 0px 0px hsl(0 0% 100% / 1), 1px 1px 0px 1px hsl(0 0% 0% / 1);
--shadow: 4px 4px 0px 0px hsl(0 0% 100% / 1);
--shadow-md: 4px 4px 0px 0px hsl(0 0% 100% / 1), 4px 2px 4px -1px hsl(0 0% 0% / 1);
/* --shadow-lg removed with the light block (F-10) */
/* press poses — same minus-1px law as the light block above */
--shadow-xs-press: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-sm-press: 1px 1px 0px 0px hsl(0 0% 100% / 1), 0px 0px 0px 1px hsl(0 0% 0% / 1);
--shadow-md-press: 3px 3px 0px 0px hsl(0 0% 100% / 1), 3px 1px 4px -1px hsl(0 0% 0% / 1);
/* elevation grammar, dark side: same geometry rung for rung, the
ink inverted to white (the white-shadow law); --shadow-paper is
theme-INDEPENDENT (paper stays white — see the light block).
The engrave duet inverts BOTH inks (the law's mechanical face —
the glow wall's black on dark reads as the carved sheen) */
--jx-engrave-shade: hsl(0 0% 100% / 0.4);
--jx-engrave-glow: hsl(0 0% 0% / 0.96);
--shadow-engrave: inset 1px 1px 0px 0px var(--jx-engrave-shade),
inset -1px -1px 0px 0px var(--jx-engrave-glow);
--shadow-well: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--shadow-well-hover: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.28);
/* floating-surface law, dark side: inverted — scrims and the shadow
layer are semi-transparent WHITE and BRIGHTEN (the white-shadow
law; same 0.32 veil strength as light mode's black) */
--scrim: hsl(0 0% 100% / 0.1);
--surface-shadow: oklch(0 0 0 / 0.32); /* black — r14-17, Owner */
/* ── the surface ladder, dark side (explicit-props §7 / task 1.1):
the M3 dark law — shadows are weak here, the STEPS carry the
hierarchy; the rungs LIGHTEN upward, away from the page void,
and stay below --card (0.3211 — the existing panel tokens keep
their place above the ladder). 减色墨律: role steps, never
overlays. This block feeds the generated prefers-color-scheme
projection in jx-pure.css (gen-jx-auto-dark — single source). */
--surface: var(--background);
--surface-container-lowest: oklch(0.115 0 0);
--surface-container-low: oklch(0.185 0 0);
--surface-container: oklch(0.205 0 0);
--surface-container-high: oklch(0.245 0 0);
--surface-container-highest: oklch(0.29 0 0);
--surface-concave: var(--background);
/* ── the elevation level table, dark side (explicit-props §0.1/§7 /
task 1.2): geometry pinned rung for rung with light (the
2026-09-01 law — sizes never drift between themes), the ink
inverted to white at reduced alpha — the soft-lens compensation
(dark hierarchy rides the LADDER; full-alpha white glow through
a 12px blur would wash it). level-1 keeps the inset duet's
single shade wall at the well-tier strength. */
--jx-elevation-level-1-shadow:
inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--jx-elevation-level-1-surface: var(--surface-concave);
--jx-elevation-level0-shadow: none;
--jx-elevation-level0-surface: var(--surface);
--jx-elevation-level1-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 1px 3px 1px hsl(0 0% 100% / 0.08);
--jx-elevation-level1-surface: var(--surface-container-lowest);
--jx-elevation-level2-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 2px 6px 2px hsl(0 0% 100% / 0.08);
--jx-elevation-level2-surface: var(--surface-container-low);
--jx-elevation-level3-shadow:
0px 1px 3px 0px hsl(0 0% 100% / 0.16),
0px 4px 8px 3px hsl(0 0% 100% / 0.08);
--jx-elevation-level3-surface: var(--surface-container);
--jx-elevation-level4-shadow:
0px 2px 3px 0px hsl(0 0% 100% / 0.16),
0px 6px 10px 4px hsl(0 0% 100% / 0.08);
--jx-elevation-level4-surface: var(--surface-container-high);
--jx-elevation-level5-shadow:
0px 4px 4px 0px hsl(0 0% 100% / 0.16),
0px 8px 12px 6px hsl(0 0% 100% / 0.08);
--jx-elevation-level5-surface: var(--surface-container-highest);
/* the color axis' effective carrier — dark's own --primary (the
hue-drifted one; re-declared per theme scope, the canvas-bug
law) */
--jx-color-effective: var(--primary);
color-scheme: dark;
}
/* the scope-root companion: without it B0's color-scheme: light would
out-shout the inherited root scheme and native pickers/scrollbars
would stay light under dark tokens (the inverted-A2 bug) */
:where(.jx-auto-dark) :where(.jx-pure):not(.jx-light, .jx-light *):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
}
/* ==== END GENERATED · jx-auto-dark ==== */
law
Validation states — the aria-invalid matrix
The Pico state contract on the SEMANTIC palette (success / warning / info / error tokens now in jixoai.css): aria-invalid='false' leans --success ('✓' ink glyph + success border); aria-invalid='true' flips every accent to --error (dashed lanes + '!' ink, checked checkbox/radio fills, the switch track, the range fill + thumb). --destructive is untouched — it stays the monochrome inversion pair for destructive actions. Native :invalid is deliberately NOT hooked.
jx-pure · validation — the aria-invalid matrix
The Pico state contract on the semantic palette: aria-invalid='false' leans --success; aria-invalid='true' flips every accent to --error (dashed lanes, checked fills, the switch track, the range fill + thumb). --destructive is untouched. Native :invalid is deliberately NOT hooked.
/**
* jx-pure — the face of jixoai-ui (registry/files/theme/jx-pure.css).
*
* V3 (css-laws, 2026-08-28): the native form-control laws are
* SINGLE-SOURCED as typed TS objects in packages/css-laws/src/laws.
* THIS file carries two GENERATED projections of that source (the
* @apply chain is retired — TW4 dev did not reliably emit complex
* utilities onto element selectors):
* Part A slot — the Tier-2 opt-in classes (.jx-control, .jx-slider,
* …), unlayered by design (they beat layered utilities)
* Part B slot — the bare-element defaults under :where(.jx-pure),
* inside this sheet's @layer components
* Regenerate after editing laws: npx tsx packages/css-laws/src/build.ts
* Non-form-control face laws (typography, links, buttons, fieldset,
* details, lists, tables, progress, figure, validation matrix, scope
* law) remain face-authored below.
*
* A · opt-in classes = GENERATED alias slot (css-laws)
* B · element defaults = GENERATED face slot (css-laws) + face-authored laws
* C · degradation laws (face-owned transitions only)
* D · auto-dark (GENERATED by scripts/gen-jx-auto-dark.mjs)
*
* Scope law: .jx-pure is a subtree wrapper — it never reaches into
* shadow roots (CustomElements must @import this sheet inside their
* own shadow style). dialog/popover/tooltip are Tier-2 territory.
*/
/* =====================================================================
A · OPT-IN CLASSES — @apply applications of the standard layer
(the declarations live once in jixoai.css; these selectors only
bind them to the opt-in vocabulary)
===================================================================== */
/* opt-in classes = GENERATED applications of the standard layer
(the declarations live once in packages/css-laws/src/laws; these
selectors bind them to the opt-in vocabulary — Tier-2, unlayered
by design: they beat layered utilities) */
/* @jixoai/css-laws:begin:jx-html-alias — GENERATED, do not edit (source: packages/css-laws/src/laws) */
.jx-slider {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
.jx-slider::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider:dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
.jx-slider[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
.jx-slider:focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
.jx-slider:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-color-swatch {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
.jx-color-swatch::-webkit-color-swatch-wrapper {
padding: 0;
}
.jx-color-swatch::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
.jx-color-swatch::-moz-color-swatch {
border: 0;
border-radius: 0;
}
.jx-tgroup {
corner-shape: var(--corner-shape, bevel);
display: inline-flex;
width: fit-content;
flex-wrap: wrap;
overflow: hidden;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--card);
box-shadow: var(--shadow-2xs);
}
.jx-tgroup> label {
display: inline-flex;
align-items: center;
min-block-size: var(--jx-hit, 2.5rem);
padding-block: calc((var(--jx-hit, 2.5rem) - var(--jx-line, 1.25rem)) / 2);
padding-inline: var(--jx-inset, 0.75rem);
font-family: var(--font-nav);
font-size: var(--jx-text, 0.8125rem);
line-height: var(--jx-line, 1.25rem);
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted-foreground);
background-color: transparent;
border-inline-end: 1px solid var(--border);
cursor: pointer;
user-select: none;
transition: color 150ms ease-out, background-color 150ms ease-out;
}
.jx-tgroup> label:last-child {
border-inline-end: 0;
}
.jx-tgroup> label:not(:has(input:disabled)):hover {
color: var(--foreground);
}
.jx-tgroup> label:has(input:checked) {
background-color: var(--primary);
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:checked):not(:has(input:disabled)):hover {
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-tgroup> label:has(input:disabled) {
cursor: not-allowed;
opacity: 0.45;
}
.jx-tgroup> label > input {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.jx-tgroup[data-chrome='bare'] {
border: 0;
background: transparent;
box-shadow: none;
border-radius: 0;
overflow: visible;
}
.jx-tgroup[data-chrome='bare'] > label {
border-inline-end: 0;
flex: 1 1 auto;
justify-content: center;
}
.jx-tgroup[data-chrome='bare'] > label:not(:has(input:disabled)):hover {
color: var(--foreground);
background-color: color-mix(in oklab, var(--muted) 55%, transparent);
}
@media (prefers-reduced-motion: reduce) {
.jx-tgroup> label {
transition: none;
}
}
.jx-control {
box-sizing: border-box;
display: block;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding: var(--jx-gap, 0.5rem) var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font-size: var(--jx-text, 0.875rem);
color-scheme: light;
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control:focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
.jx-control:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-control[aria-invalid='true'] {
border-style: dashed;
border-color: var(--error);
color: var(--error);
}
.jx-control[aria-invalid='false'] {
border-color: var(--primary);
}
.jx-control::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control[type='email'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
.jx-control {
transition: none;
}
}
.jx-control-shell {
box-sizing: border-box;
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
font-size: var(--jx-text, 0.875rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
box-shadow: var(--shadow-well);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control-shell:has(> .jx-html-clear:last-child) {
padding-inline-end: 0;
}
.jx-control-shell:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control-shell:has(:focus) {
border-color: var(--ring);
}
.jx-control-shell:has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-control-shell:has([aria-invalid='true']), .jx-control-shell.jx-invalid {
border-style: dashed;
}
.jx-control-shell:has(:disabled) {
border-color: var(--muted);
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
.jx-control-shell {
transition: none;
}
}
.jx-control-lane {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
padding: 0;
outline: none;
background: transparent;
color: var(--foreground);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
}
.jx-control-lane::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control-lane::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control-lane[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control-lane[type='email'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
/* @jixoai/css-laws:end:jx-html-alias */
.jx-control-shell.jx-slotted {
padding-inline: var(--jx-inset, 0.75rem);
}
.jx-control-shell .jx-control-lane {
padding-inline: 0;
}
.jx-field {
display: flex;
flex-direction: column;
gap: var(--jx-stack, 0.5rem);
width: 100%;
min-width: 0;
}
.jx-label {
font-family: var(--font-nav);
/* secondary-text is a density ROLE (density-adoption §3): the label
* tracks the ambient scope instead of a fixed 11px (2026-08-29) */
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
cursor: pointer;
}
.jx-error {
display: flex;
align-items: center;
gap: 0.25rem;
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--destructive);
}
.jx-error-mark {
font-weight: bold;
}
/* the shell carries NO chrome itself (final-check ruling): the box
* chrome — border AND fill — lives on a ::before BAND whose height
* matches the -webkit-color-swatch-wrapper (the actual color chip's
* lane). 2026-08-29: the fill moved OFF the shell — an element-painted
* background leaks a full-height rectangle that ears out above/below
* the band on any surface where ambient ≠ --background (cards,
* panels, dark); the band now fills itself.
*
* GEOMETRY LAW (final-check ruling 2, the checkbox/range precedent):
* the chip is a LOCKED size-and-ratio block — height = the hit lane,
* aspect 7:4 (≈4.8rem at the 2.75rem hit — visually balanced, NOT a
* literal width), and the shell is its own SIZE CONTAINER: every
* internal geometry derives from 100cqh, so a density change (or a
* consumer height override) scales the whole chip proportionally —
* the swatch circle, the band, the pill radius, the glyph. The hit
* token sets ONLY the height; nothing else reads it. */
.jx-color-shell {
display: flex;
flex: none;
/* the shell's internal ladder (swatch z1, pipette ::after z2, the
custom-picker overlay z1) is COMPONENT-PRIVATE: container-type
does NOT establish a stacking context (measured, the isolation
clause 2026-09-09), so the shell roots it explicitly — the
deferred class-(a) tail cleared */
isolation: isolate;
/* fit-content protects the ratio-derived width from stretch (grid
tracks, block flow) while aspect-ratio + the locked height keep
it the chip's intrinsic 7:4 */
width: fit-content;
height: var(--jx-hit, 2.5rem);
aspect-ratio: 7 / 4;
container-type: size;
cursor: pointer;
position: relative;
transition: box-shadow 150ms ease-out;
}
.jx-color-shell::before {
content: '';
position: absolute;
inset-inline: 0;
inset-block: calc(100cqh / 6);
border: 1px solid var(--border);
background: var(--background);
pointer-events: none;
corner-left-shape: round;
/* band height = 100cqh − 2×(100cqh/6) = 100cqh × 2/3 — half of it
is the true-semicircle pill radius (no clamp hack) */
border-top-left-radius: calc(100cqh / 3);
border-bottom-left-radius: calc(100cqh / 3);
corner-right-shape: bevel;
/* the right radius rides the SAME cq quantum as the band inset
(100cqh/6 ≈ 8px at the default hit — was var(--radius, 8px),
which froze while every other edge scaled with the container;
B4: no internal dimension outside cq units) */
border-top-right-radius: calc(100cqh / 6);
border-bottom-right-radius: calc(100cqh / 6);
}
.jx-color-expand {
/* both dimensions definite → aspect-ratio yields; the chip keeps
its locked height across the full row.
FLEX PARTICIPATION is re-opened here on purpose: the base shell's
flex:none protects the COMPACT chip, but it also beats any layered
flex utility (this zone is unlayered) — so width:100% alone would
size against the WHOLE flex container and overflow any sibling
(the Tier-1 demo row, 2026-08-29: 77+12+329 > 329). grow reclaims
the full row, shrink shares it; block flow is untouched. */
width: 100%;
flex: 1 1 auto;
}
.jx-color-shell:has([aria-invalid='true'])::before,
.jx-color-shell.jx-invalid::before {
border-style: dashed;
}
.jx-color-shell .jx-color-swatch {
position: relative;
z-index: 1;
flex: none;
/* the chip lane = the container's full height; the swatch circle
inside sizes from the input's own padding (also cqh-relative) */
width: 100cqh;
height: auto;
align-self: stretch;
border: 0;
border-inline-end: 1px solid var(--border);
padding: calc(100cqh / 6);
}
.jx-color-shell .jx-color-swatch:focus-visible {
outline: none;
}
/* clear button: SUPERSEDED by jx-html-clear in the standard layer */
/* @jixoai/css-laws:begin:jx-icon-vocab — GENERATED, do not edit (source: packages/css-laws/src/icon-vocab) */
/* the pipette glyph — an ICON SLOT on the WRAPPER (input[type=color]
* is a replaced element whose ::after is unreliable across engines;
* the label wrapper is non-replaced and paints reliably) */
.jx-color-shell::after {
content: '';
position: absolute;
/* decorative carrier (the law's TRANSIENT INK family) + a ladder
rung — z2 orders against the swatch z1 INSIDE the shell, whose
own isolation: isolate roots the ladder (the isolation clause,
2026-09-09; the shell rule lives in the hand zone above) */
z-index: 2;
/* proportional optics: glyph ≈ 36% of the lane, end inset ≈ 27% —
scale with the container, not with font size */
inset-inline-end: calc(100cqh * 0.27);
top: 50%;
width: calc(100cqh * 0.36);
height: calc(100cqh * 0.36);
translate: 0 -50%;
color: var(--muted-foreground);
background-color: currentColor;
-webkit-mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
pointer-events: none;
}
.jx-color-shell:hover::after {
color: var(--foreground);
}
/* the color-picker chevron — an ICON SLOT (mask, currentColor themes) */
.jx-color-picker-chevron {
display: block;
width: 0.75rem;
height: 0.75rem;
background-color: currentColor;
-webkit-mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
}
/* =====================================================================
Icon vocabulary — the mask/currentColor law. One alpha-only URI per
glyph; the encoded stroke %23000 is an ALPHA SOURCE ONLY. The INK
variants (calendar/clock/valid/invalid) serve UA-shadow pseudos that
reject author mask paint; .dark flips them to %23fff, .jx-light back.
===================================================================== */
@layer theme {
:root {
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* THEME-SCOPED placeholder (canvas bug, Owner 2026-09-04 — same law
as the variant-grammar slots in jixoai.css): custom properties
substitute their var() at the DECLARING element — a :root-only
--jx-placeholder handed every descendant the root's
already-substituted mix, so a scoped .dark/.jx-light
(component-canvas stage, terminal-card, print) flipping
--foreground/--background never re-flipped the placeholder ink
with it. The selector list re-declares the slot ON each theme
scope: one declaration point, zero duplicates */
:root,
.jx-light,
.dark {
--jx-placeholder: color-mix(in oklab, var(--foreground) 40%, var(--background));
}
}
.dark {
/* the author-painted icon set flips to white ink in dark (the
-ink quartet's law extended to the plain slots the input/select
laws consume — black alpha URIs vanish on the dark token sheet) */
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
.jx-light {
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* @jixoai/css-laws:end:jx-icon-vocab */
/* =====================================================================
The zero-class STRUCTURAL input group: a label wrapping a text-like
control AND at least one span composes into the shell — the label
takes the box law, the spans ride as prefix/suffix cells, the
control goes chromeless. NO opt-in class needed.
===================================================================== */
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) {
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
padding-inline: var(--jx-inset, 0.75rem);
cursor: text;
transition: box-shadow 150ms ease-out;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):hover {
box-shadow: var(--shadow-2xs);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > span {
display: inline-flex;
align-items: center;
flex: none;
font-size: var(--jx-text, 0.875rem);
color: var(--muted-foreground);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > input {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
outline: none;
background: transparent;
color: var(--foreground);
font: inherit;
font-size: var(--jx-text, 0.875rem);
padding-inline: 0;
}
/* =====================================================================
Switch size modifiers (face-owned; the standard utility carries the
density-alias default, these opt into explicit sizes)
===================================================================== */
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-sm:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-sm input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 2rem;
--jx-toggle-track: 1.25rem;
--jx-toggle-knob: 0.75rem;
}
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-lg:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-lg input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 3rem;
--jx-toggle-track: 1.5rem;
--jx-toggle-knob: 1.25rem;
}
/* =====================================================================
Bare color input: the locked square standalone (without a .jx-color-
shell wrapper)
===================================================================== */
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: calc(var(--jx-hit, 2.5rem) - 2px);
padding: 2px;
}
/* =====================================================================
Reduced-motion law: the sheet's face-owned transitions neutralize.
===================================================================== */
@media (prefers-reduced-motion: reduce) {
.jx-control,
.jx-control-shell,
.jx-color-shell {
transition: none;
}
}
/* =====================================================================
B · ELEMENT DEFAULTS — the .jx-pure subtree face.
Every rule rides :where(.jx-pure) so the scope class contributes
ZERO specificity inside @layer components: Tailwind utilities
(utilities layer) and any unlayered author css override these
cheaply, and non-Tailwind static consumers override with plain
css. Colors come from tokens or currentColor ONLY — no hardcoded
paint survives a theme flip.
===================================================================== */
@layer components {
/* ---- B0 · the scope root: color-scheme follows the theme classes
the token sheet owns. color-scheme INHERITS — one declaration
themes every native picker, scrollbar and form control in the
subtree: light under :root, dark under .dark (ancestor or self),
forced light under .jx-light. */
:where(.jx-pure):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
/* density adoption (native-contract-fusion Phase 5): the scope
root rides the density interface's text/leading aliases (the
typography LADDER above keeps its fixed steps — declared gap) */
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.6);
}
:where(.dark) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.dark):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
:where(.jx-light) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.jx-light):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
}
/* =====================================================================
B1 · Typography — documented rem steps (the repo ships no
typography size tokens; these literals ARE the scale until a
token ruling lands — do not scatter new sizes elsewhere). The
flow margins are EXPLICIT because preflight zeroes them: a
Tailwind host without this block would render wall-of-text prose.
===================================================================== */
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6):not(.no-jx-pure, .no-jx-pure *) {
margin: 1.5em 0 0.6em;
font-weight: 700;
line-height: 1.25;
color: var(--foreground);
}
:where(.jx-pure) h1:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.875rem;
}
:where(.jx-pure) h2:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.5rem;
}
:where(.jx-pure) h3:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.25rem;
}
:where(.jx-pure) h4:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.125rem;
}
:where(.jx-pure) :where(h5, h6):not(.no-jx-pure, .no-jx-pure *) {
font-size: 1rem;
}
:where(.jx-pure) :where(p, ul, ol, dl, blockquote, pre, table, hr):not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
}
:where(.jx-pure) p:not(.no-jx-pure, .no-jx-pure *) {
line-height: 1.6;
}
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6) :where(p, ul, ol, dl, blockquote, pre, table):first-child:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0;
}
:where(.jx-pure) small:not(.no-jx-pure, .no-jx-pure *) {
font-size: 0.8125rem;
color: var(--muted-foreground);
}
:where(.jx-pure) :where(strong, b):not(.no-jx-pure, .no-jx-pure *) {
font-weight: 700;
}
:where(.jx-pure) blockquote:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-start: 0.875rem;
border-inline-start: 1px solid var(--border);
color: var(--muted-foreground);
}
:where(.jx-pure) :where(code, kbd, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.1em 0.4em;
border: 1px solid var(--border);
background: var(--muted);
font-family: var(--font-mono);
font-size: 0.8125rem;
}
:where(.jx-pure) kbd:not(.no-jx-pure, .no-jx-pure *) {
/* the key cap is ENGRAVED, not lifted (F-2, adversarial-review
2026-09-02 — Owner kbd ruling): --shadow-engrave inset, the
elevation grammar's engrave tier, unified with the registry kbd
component (shadow-engrave). The old `0 1px 0 var(--border)`
lifted-edge dialect is retired — one kbd face across the bare
element and the component. */
box-shadow: var(--shadow-engrave);
}
:where(.jx-pure) pre:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.75rem 1rem;
border: 1px solid var(--border);
background: var(--background);
overflow: auto;
font-family: var(--font-mono);
font-size: 0.8125rem;
line-height: 1.55;
}
/* the code-in-pre lane drops its inline box — the pre owns the box */
:where(.jx-pure) pre :where(code, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0;
border: 0;
background: transparent;
font-size: inherit;
}
:where(.jx-pure) mark:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.05em 0.25em;
background: color-mix(in oklab, var(--secondary) 45%, var(--background));
color: var(--foreground);
}
:where(.jx-pure) hr:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 1.5rem;
border: 0;
border-top: 1px solid var(--border);
}
/* =====================================================================
B2 · Links — the site link law (press-button link variant):
primary text, no underline at rest, underline on hover. Nav links
read as chrome, not prose: foreground at rest, primary + underline
as the hover cue.
===================================================================== */
:where(.jx-pure) a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-underline-offset: 4px;
}
:where(.jx-pure) a:hover:not(.no-jx-pure, .no-jx-pure *) {
text-decoration-line: underline;
}
:where(.jx-pure) nav a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--foreground);
}
:where(.jx-pure) nav a:hover:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-decoration-line: underline;
}
/* =====================================================================
B3 · Buttons — the .jx-press physics restated element-scoped
(hover grows the token shadow + bg-muted; active presses +1px
into the page with the *-press twin — same variable contract,
no WAAPI, no second geometry law). .jx-button is the EXPLICIT
channel for link-look buttons (Codex D2: never auto-style
a[role=button] — CSS cannot add command semantics). Focus is
deliberately NOT set here: the host's focus law owns it (site
base layer paints a/button; static pages keep the UA ring).
===================================================================== */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *) {
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.375rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 1rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
line-height: 1.45;
text-decoration: none;
cursor: pointer;
box-shadow: var(--jx-press-shadow, var(--shadow-xs));
transition:
translate 150ms ease-out,
box-shadow 150ms ease-out,
background-color 150ms ease-out,
border-color 150ms ease-out,
color 150ms ease-out;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):hover:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
box-shadow: var(--jx-press-shadow-hover, var(--shadow-sm));
}
/* :active LAST — at equal specificity the later rule wins the hover pose */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: 1px 1px;
box-shadow: var(--jx-press-shadow-active, var(--shadow-sm-press));
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
cursor: not-allowed;
box-shadow: none;
}
/* =====================================================================
B4+B5 · form controls = @apply applications of the standard
layer (the 13-type allowlist rides each selector; the number lane
keeps the PLATFORM stepper by sharing jx-html-input; checkbox
excludes [role=switch] so the switch gets its own utility) ----- */
/* GENERATED between the markers (css-laws V3): the bare-element
defaults — same declaration source as the .jx-html-* classes,
serialized as element-default rules under :where(.jx-pure) */
/* @jixoai/css-laws:begin:jx-html-face — GENERATED, do not edit (source: packages/css-laws/src/laws) */
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-textarea-min, 5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
height: auto;
resize: vertical;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
--jx-icon-chevron-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
cursor: pointer;
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):disabled, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
@supports not selector(::-moz-range-progress) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
background-image: var(--jx-icon-chevron, var(--jx-icon-chevron-svg));
background-position: right var(--jx-inset, 0.75rem) center;
background-size: var(--jx-icon, 1.25rem);
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
filter: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]) {
min-height: 5.75rem;
padding-block: 0.375rem 0.5rem;
cursor: default;
background-image: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
cursor: pointer;
transition: background-color 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate::before {
opacity: 1;
transform: rotate(0deg);
clip-path: polygon(10% 40%, 10% 60%, 45% 60%, 55% 60%, 90% 60%, 90% 40%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked, :where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate {
background: var(--primary);
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 50%;
background: var(--background);
cursor: pointer;
transition: border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
content: none;
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::after {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
border-radius: 50%;
background: var(--primary);
transform: scale(0);
transition: transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::after {
transform: scale(1);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--background);
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
position: relative;
width: var(--jx-toggle-width, 2.5rem);
height: var(--jx-toggle-track, 1.5rem);
margin: 0;
flex: none;
padding: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
border: 0;
box-shadow: 0 0 0 1px var(--border) inset;
border-radius: calc(infinity * 1px);
background: var(--muted);
cursor: pointer;
transition: background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
inset-block: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inset-inline-start: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inline-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
block-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
border-radius: calc(infinity * 1px);
border: var(--jx-toggle-knob-border, 1px) solid var(--jx-toggle-knob-border-color, var(--primary));
background: var(--background);
transform: translateX(0);
transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1), background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), border-color 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
transform: translateX(calc(var(--jx-toggle-width, 2.5rem) - var(--jx-toggle-track, 1.5rem)));
background: var(--primary-foreground);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
box-shadow: 0 0 0 1px var(--primary) inset;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)) {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch-wrapper {
padding: 0;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-moz-color-swatch {
border: 0;
border-radius: 0;
}
/* @jixoai/css-laws:end:jx-html-face */
/* ---- B6 · label / fieldset / legend (face-owned; not form-
control law — the one-opacity-owner disabled law) -------------
===================================================================== */
:where(.jx-pure) label:not(.no-jx-pure, .no-jx-pure *) {
cursor: pointer;
}
:where(.jx-pure) fieldset:not(.no-jx-pure, .no-jx-pure *) {
min-width: 0;
margin-block: 0.75rem;
padding: 0.875rem 1rem 1rem;
border: 1px solid var(--border);
border-radius: 0;
}
:where(.jx-pure) fieldset:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* ONE opacity owner per subtree (Codex review A3): the group dims to
.5 and the controls inside stay at 1 — two stacked .5 layers
composite to ~.25 and the contrast collapses */
:where(.jx-pure) fieldset:disabled :where(input, textarea, select, button):not(.no-jx-pure, .no-jx-pure *) {
opacity: 1;
cursor: not-allowed;
}
:where(.jx-pure) legend:not(.no-jx-pure, .no-jx-pure *) {
padding-inline: 0.5rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* =====================================================================
B7 · details / summary — document-flow disclosure ONLY (dialog /
popover / tooltip stay Tier-2, Codex D3). Static marker swap, no
open/close animation (progressive enhancement deferred); the
visible focus ring is never replaced by the marker.
===================================================================== */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *) {
display: flex;
align-items: center;
gap: 0.625rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
font-size: 0.875rem;
list-style: none;
cursor: pointer;
transition:
border-color 150ms ease-out,
box-shadow 150ms ease-out;
}
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::-webkit-details-marker {
display: none;
}
/* the marker: a bordered square holding + / − (static swap) */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '+';
box-sizing: border-box;
display: grid;
place-items: center;
width: 1.125rem;
height: 1.125rem;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--muted-foreground);
font-family: var(--font-nav);
font-size: 12px;
line-height: 1;
}
:where(.jx-pure) details[open] > summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '−';
}
:where(.jx-pure) summary:hover:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--primary); /* leans like the checkbox border */
}
:where(.jx-pure) summary:focus-visible:not(.no-jx-pure, .no-jx-pure *) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) details > * + *:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.5rem;
}
/* =====================================================================
B8 · lists / dl — restore the document-flow markers preflight
removes (classless parity) and theme them; nav's link law lives
in B2.
===================================================================== */
:where(.jx-pure) ul:not(.no-jx-pure, .no-jx-pure *) {
list-style: disc;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) ol:not(.no-jx-pure, .no-jx-pure *) {
list-style: decimal;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) li:not(.no-jx-pure, .no-jx-pure *)::marker {
color: var(--muted-foreground);
}
:where(.jx-pure) dl:not(.no-jx-pure, .no-jx-pure *) {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.375rem 1rem;
}
:where(.jx-pure) dt:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
:where(.jx-pure) dd:not(.no-jx-pure, .no-jx-pure *) {
margin: 0;
}
/* =====================================================================
B9 · Tables — the bordered grid law.
===================================================================== */
:where(.jx-pure) table:not(.no-jx-pure, .no-jx-pure *) {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
:where(.jx-pure) caption:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.375rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
caption-side: bottom;
text-align: start;
}
:where(.jx-pure) :where(th, td):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
text-align: start;
}
:where(.jx-pure) th:not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
font-family: var(--font-nav);
font-size: 11px;
font-weight: 400;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
white-space: nowrap;
}
:where(.jx-pure) tbody tr:hover:not(.no-jx-pure, .no-jx-pure *) {
background: color-mix(in oklab, var(--muted) 26%, transparent);
}
/* =====================================================================
B10 · progress / meter / output (Owner completion round, 2026-08-24:
the Codex D6 deferral is overruled — the contracts exist now).
progress: the range-track geometry (8px bordered box, primary
fill); indeterminate trades the fill for a sliding stripe, fully
static under reduced motion. meter: the same box with the
SEMANTIC token mapping — optimum=primary, suboptimal=secondary,
even-less-good=destructive (no hardcoded traffic lights). output:
the mono result lane. Engine pseudos live in SEPARATE rules (the
R1 law: a shared -moz list is dropped whole by Chromium).
===================================================================== */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *) {
display: block;
box-sizing: border-box;
width: 100%;
height: 0.5rem; /* the 8px track family (incl. borders) */
margin: 0;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
appearance: none;
-webkit-appearance: none;
overflow: hidden;
}
:where(.jx-pure) progress:disabled:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* chromium: the track pseudo + the value pseudo */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-bar {
background: var(--background);
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-value {
background: var(--primary);
transition: width 150ms ease-out;
}
/* indeterminate: no percent exists — a muted stripe slides across.
The stripe rides the ELEMENT's own background, never the UA
pseudos: engines reject author paint/animation on progress
pseudos exactly like the number spinners (Codex r4 R4-1 — the
pseudo path compiled but never animated). Part C parks it under
reduced motion. */
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *) {
background:
linear-gradient(in oklab, var(--muted), var(--muted)) 0 0 / 40% 100% no-repeat,
var(--background);
animation: jx-progress-slide 1.2s linear infinite;
}
/* firefox: the element is the track; the bar pseudo is the value */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: var(--primary);
}
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: transparent; /* the element's stripe owns the paint */
}
/* meter: the semantic three-state fill (token-mapped, monochrome law) */
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-bar {
background: var(--background);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-optimum-value {
background: var(--primary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-suboptimum-value {
background: var(--secondary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-even-less-good-value {
background: var(--destructive);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--primary);
}
:where(.jx-pure) meter:-moz-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--secondary);
}
:where(.jx-pure) meter:-moz-sub-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--destructive);
}
/* the stripe keyframes live OUTSIDE the layer's rule bodies… they
are defined once here (keyframes are global; the jx- prefix keeps
the namespace) — declared at the layer's end so both engine rules
above can reference them */
}
@keyframes jx-progress-slide {
from {
background-position: -40% 0, 0 0;
}
to {
background-position: 140% 0, 0 0;
}
}
@layer components {
/* output: the calculation result lane — mono, foreground, inline */
:where(.jx-pure) output:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-mono);
font-size: 0.875rem;
color: var(--foreground);
}
/* =====================================================================
B11 · figure / media — the documentation flow. figure carries the
flow margin + the bordered plate; figcaption rides the caption
law (nav font, small caps, muted, below). Media never overflows
its lane.
===================================================================== */
:where(.jx-pure) :where(img, video):not(.no-jx-pure, .no-jx-pure *) {
max-width: 100%;
height: auto;
}
:where(.jx-pure) figure:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.375rem;
max-width: 100%;
}
:where(.jx-pure) figure > :where(img, video, svg, pre, table):not(.no-jx-pure, .no-jx-pure *) {
border: 1px solid var(--border);
}
:where(.jx-pure) figcaption:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* ---- B13 · switch = @apply application (the ONE input law;
[role=switch] discriminates it from the checkbox) ------------- */
/* the label posture: a wrapping label dims with its input */
:where(.jx-pure) label:has(> input[type='checkbox'][role='switch']):not(.no-jx-pure, .no-jx-pure *) {
display: inline-flex;
align-items: center;
gap: var(--jx-gap, 0.5rem);
cursor: pointer;
user-select: none;
min-block-size: var(--jx-hit, 2.5rem);
&:has(input:disabled) {
cursor: not-allowed;
opacity: 0.5;
}
}
/* =====================================================================
B14 · validation states — the Pico state matrix on the SEMANTIC
palette (openspec D5): aria-invalid='false' leans --success ('✓'
ink + success border + success hover lean); aria-invalid='true'
flips every accent to --error (dashed lanes + '!' ink, checked
fills, the radio DOT, switch track, range fill + thumb).
--destructive is NOT used here — it stays the monochrome
inversion pair for destructive actions. Native :invalid stays
deliberately unhooked (no empty-required surprises).
===================================================================== */
/* lanes: border-color states + the ink glyphs */
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
background-image: var(--jx-icon-invalid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: 2rem;
background-image: var(--jx-icon-valid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
/* checkbox / radio: the checked accent flips to error */
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:indeterminate:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::after {
background: var(--error-foreground);
}
:where(.jx-pure) input[type='checkbox'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success); /* the valid lean */
}
/* switch: the checked track flips */
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::before {
border-color: transparent;
}
/* range: fill + thumb flip */
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
--jx-slider-fill-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-webkit-slider-thumb {
border-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-moz-range-thumb {
background: var(--error);
}
}
/* =====================================================================
B12 · the reverse scope — .no-jx-pure (Owner third revision,
2026-08-24): the r8/r9 `all: revert !important` hatch was too
violent — it also rolled back the HOST's own utilities and inline
styles. Every face rule now carries the exclusion on its subject:
:not(.no-jx-pure, .no-jx-pure *) — an element that IS, or lives
inside, a no-jx-pure subtree never receives the face; everything
the host authored there is untouched. Part A opt-in classes still
work inside islands (author intent, not face paint). INHERITED
properties (color-scheme, custom property tokens) keep flowing
through islands from ancestors — the exclusion is element-level
paint, never a war against the page's theme or the host.
=====================================================================
*/
/* =====================================================================
C · DEGRADATION LAWS — motion and forced colors.
===================================================================== */
/* Reduced motion: FULL STILLNESS, not zero-duration animation (Codex
review B): every Part B transition goes none AND the interactive
displacements (the press translate, the thumb press transform) are
pinned back to their rest poses so nothing ever moves. */
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) :where(textarea, select):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
/* engine pseudos NEVER share a selector list — a non-forgiving list
with an unknown -moz pseudo is dropped WHOLE by Chromium (Codex
r2 R1); one rule per engine surface */
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
/* the indeterminate stripe parks: element animation off (the
authored -moz pseudo animation is likewise killed — one rule per
surface, and the -moz one stands alone) */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *) {
animation: none;
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
animation: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
:where(.jx-pure) input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
transition: none;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: none;
}
}
/* Forced colors (Windows High Contrast & friends): the custom-painted
controls revert to appearance:auto so the SYSTEM palette and glyphs
speak — author paint would flatten into the forced canvas and lose
the checked/unchecked distinction entirely. Box laws (borders,
outlines) survive: forced-colors keeps author borders as system
colors. The opt-in select ALSO drops its gradient chevron or the
restored platform arrow would double up with the leftover paint. */
@media (forced-colors: active) {
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='range']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='color']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select:not(.no-jx-pure, .no-jx-pure *) {
appearance: auto;
-webkit-appearance: auto;
background-image: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before,
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
content: none;
}
}
/* ==== BEGIN GENERATED · jx-auto-dark — scripts/gen-jx-auto-dark.mjs (do not hand-edit) ==== */
/* Derived 1:1 from jixoai.css's .dark block (single source). The gate
rides :where() so the whole variant stays maximally overridable; it
never fires where an explicit .dark already owns the theme, nor
inside .jx-light islands. Mount: <html class="jx-pure jx-auto-dark"> */
@media (prefers-color-scheme: dark) {
:where(.jx-auto-dark):not(.dark, .jx-light *) {
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--terminal: oklch(0.2 0 0);
--terminal-foreground: oklch(1 0 0);
--terminal-hover: color-mix(in oklab, var(--terminal-foreground) 14%, var(--terminal));
--terminal-muted: color-mix(in oklab, var(--terminal-foreground) 8%, var(--terminal));
--card: oklch(0.3211 0 0);
--card-foreground: oklch(1 0 0);
--popover: oklch(0.3211 0 0);
--popover-foreground: oklch(1 0 0);
/* the primary hue drifts -4° toward dark, mirroring the reference */
--primary: oklch(0.7044 0.1872 calc(var(--brand-hue) - 4));
--primary-foreground: oklch(0 0 0);
--primary-text: var(--primary);
--secondary: oklch(0.9691 0.2005 109.6228);
--secondary-foreground: oklch(0 0 0);
--muted: oklch(0.2178 0 0);
--muted-foreground: oklch(0.8452 0 0);
--accent: oklch(0.6755 0.1765 252.2592);
--accent-foreground: oklch(0 0 0);
--destructive: oklch(1 0 0);
--destructive-foreground: oklch(0 0 0);
--border: oklch(1 0 0);
--input: oklch(1 0 0);
--ring: var(--primary);
--success: oklch(0.72 0.16 145);
--success-foreground: oklch(0 0 0);
--warning: oklch(0.78 0.17 85);
--warning-foreground: oklch(0 0 0);
--info: oklch(0.74 0.14 245);
--info-foreground: oklch(0 0 0);
--error: oklch(0.72 0.16 25);
--error-foreground: oklch(0 0 0);
--chart-1: var(--primary);
--chart-2: var(--success);
--chart-3: var(--info);
--chart-4: var(--warning);
--chart-5: var(--error);
--shadow-color: hsl(0 0% 100%);
/* shadow GEOMETRY rides the light baseline rung for rung (Owner ruling,
2026-09-01: sizes must not drift between themes — only the INK
inverts to white; the old 4px-everywhere small rungs were copy-paste
drift, not design) */
--shadow-2xs: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-xs: 2px 2px 0px 0px hsl(0 0% 100% / 0.5);
/* ink compensation (F-11, 2026-09-02): the second layer's alpha is
deliberately NOT mirrored (0.5 light / 1.0 dark) — the black ring
rides directly on the white offset over a black ground, where
half-alpha would read as a gray smear; geometry stays rung for
rung, only the ink density compensates */
--shadow-sm: 2px 2px 0px 0px hsl(0 0% 100% / 1), 1px 1px 0px 1px hsl(0 0% 0% / 1);
--shadow: 4px 4px 0px 0px hsl(0 0% 100% / 1);
--shadow-md: 4px 4px 0px 0px hsl(0 0% 100% / 1), 4px 2px 4px -1px hsl(0 0% 0% / 1);
/* --shadow-lg removed with the light block (F-10) */
/* press poses — same minus-1px law as the light block above */
--shadow-xs-press: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-sm-press: 1px 1px 0px 0px hsl(0 0% 100% / 1), 0px 0px 0px 1px hsl(0 0% 0% / 1);
--shadow-md-press: 3px 3px 0px 0px hsl(0 0% 100% / 1), 3px 1px 4px -1px hsl(0 0% 0% / 1);
/* elevation grammar, dark side: same geometry rung for rung, the
ink inverted to white (the white-shadow law); --shadow-paper is
theme-INDEPENDENT (paper stays white — see the light block).
The engrave duet inverts BOTH inks (the law's mechanical face —
the glow wall's black on dark reads as the carved sheen) */
--jx-engrave-shade: hsl(0 0% 100% / 0.4);
--jx-engrave-glow: hsl(0 0% 0% / 0.96);
--shadow-engrave: inset 1px 1px 0px 0px var(--jx-engrave-shade),
inset -1px -1px 0px 0px var(--jx-engrave-glow);
--shadow-well: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--shadow-well-hover: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.28);
/* floating-surface law, dark side: inverted — scrims and the shadow
layer are semi-transparent WHITE and BRIGHTEN (the white-shadow
law; same 0.32 veil strength as light mode's black) */
--scrim: hsl(0 0% 100% / 0.1);
--surface-shadow: oklch(0 0 0 / 0.32); /* black — r14-17, Owner */
/* ── the surface ladder, dark side (explicit-props §7 / task 1.1):
the M3 dark law — shadows are weak here, the STEPS carry the
hierarchy; the rungs LIGHTEN upward, away from the page void,
and stay below --card (0.3211 — the existing panel tokens keep
their place above the ladder). 减色墨律: role steps, never
overlays. This block feeds the generated prefers-color-scheme
projection in jx-pure.css (gen-jx-auto-dark — single source). */
--surface: var(--background);
--surface-container-lowest: oklch(0.115 0 0);
--surface-container-low: oklch(0.185 0 0);
--surface-container: oklch(0.205 0 0);
--surface-container-high: oklch(0.245 0 0);
--surface-container-highest: oklch(0.29 0 0);
--surface-concave: var(--background);
/* ── the elevation level table, dark side (explicit-props §0.1/§7 /
task 1.2): geometry pinned rung for rung with light (the
2026-09-01 law — sizes never drift between themes), the ink
inverted to white at reduced alpha — the soft-lens compensation
(dark hierarchy rides the LADDER; full-alpha white glow through
a 12px blur would wash it). level-1 keeps the inset duet's
single shade wall at the well-tier strength. */
--jx-elevation-level-1-shadow:
inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--jx-elevation-level-1-surface: var(--surface-concave);
--jx-elevation-level0-shadow: none;
--jx-elevation-level0-surface: var(--surface);
--jx-elevation-level1-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 1px 3px 1px hsl(0 0% 100% / 0.08);
--jx-elevation-level1-surface: var(--surface-container-lowest);
--jx-elevation-level2-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 2px 6px 2px hsl(0 0% 100% / 0.08);
--jx-elevation-level2-surface: var(--surface-container-low);
--jx-elevation-level3-shadow:
0px 1px 3px 0px hsl(0 0% 100% / 0.16),
0px 4px 8px 3px hsl(0 0% 100% / 0.08);
--jx-elevation-level3-surface: var(--surface-container);
--jx-elevation-level4-shadow:
0px 2px 3px 0px hsl(0 0% 100% / 0.16),
0px 6px 10px 4px hsl(0 0% 100% / 0.08);
--jx-elevation-level4-surface: var(--surface-container-high);
--jx-elevation-level5-shadow:
0px 4px 4px 0px hsl(0 0% 100% / 0.16),
0px 8px 12px 6px hsl(0 0% 100% / 0.08);
--jx-elevation-level5-surface: var(--surface-container-highest);
/* the color axis' effective carrier — dark's own --primary (the
hue-drifted one; re-declared per theme scope, the canvas-bug
law) */
--jx-color-effective: var(--primary);
color-scheme: dark;
}
/* the scope-root companion: without it B0's color-scheme: light would
out-shout the inherited root scheme and native pickers/scrollbars
would stay light under dark tokens (the inverted-A2 bug) */
:where(.jx-auto-dark) :where(.jx-pure):not(.jx-light, .jx-light *):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
}
/* ==== END GENERATED · jx-auto-dark ==== */
law
Dark mode
Theme rides the token sheet's classes — .dark on the root (or any ancestor, or the scope itself) flips every token; the scope root carries color-scheme so native pickers and scrollbars follow. NO hand-copied tokens and NO bootstrap JS: OS-following dark for zero-JS pages is the GENERATED .jx-auto-dark variant (below). The panels are the SAME bare markup — the only difference is the theme class.
jx-pure · dark mode — the same bare markup, one class apart
Theme rides the token sheet's classes: .dark on any ancestor (or the scope itself) flips every token; .jx-light forces light under a dark root. The three panels are byte-identical markup — only the theme class differs.
/**
* jx-pure — the face of jixoai-ui (registry/files/theme/jx-pure.css).
*
* V3 (css-laws, 2026-08-28): the native form-control laws are
* SINGLE-SOURCED as typed TS objects in packages/css-laws/src/laws.
* THIS file carries two GENERATED projections of that source (the
* @apply chain is retired — TW4 dev did not reliably emit complex
* utilities onto element selectors):
* Part A slot — the Tier-2 opt-in classes (.jx-control, .jx-slider,
* …), unlayered by design (they beat layered utilities)
* Part B slot — the bare-element defaults under :where(.jx-pure),
* inside this sheet's @layer components
* Regenerate after editing laws: npx tsx packages/css-laws/src/build.ts
* Non-form-control face laws (typography, links, buttons, fieldset,
* details, lists, tables, progress, figure, validation matrix, scope
* law) remain face-authored below.
*
* A · opt-in classes = GENERATED alias slot (css-laws)
* B · element defaults = GENERATED face slot (css-laws) + face-authored laws
* C · degradation laws (face-owned transitions only)
* D · auto-dark (GENERATED by scripts/gen-jx-auto-dark.mjs)
*
* Scope law: .jx-pure is a subtree wrapper — it never reaches into
* shadow roots (CustomElements must @import this sheet inside their
* own shadow style). dialog/popover/tooltip are Tier-2 territory.
*/
/* =====================================================================
A · OPT-IN CLASSES — @apply applications of the standard layer
(the declarations live once in jixoai.css; these selectors only
bind them to the opt-in vocabulary)
===================================================================== */
/* opt-in classes = GENERATED applications of the standard layer
(the declarations live once in packages/css-laws/src/laws; these
selectors bind them to the opt-in vocabulary — Tier-2, unlayered
by design: they beat layered utilities) */
/* @jixoai/css-laws:begin:jx-html-alias — GENERATED, do not edit (source: packages/css-laws/src/laws) */
.jx-slider {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
.jx-slider::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider:dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
.jx-slider[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
.jx-slider[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
.jx-slider::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
.jx-slider::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
.jx-slider:focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
.jx-slider:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-color-swatch {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
.jx-color-swatch::-webkit-color-swatch-wrapper {
padding: 0;
}
.jx-color-swatch::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
.jx-color-swatch::-moz-color-swatch {
border: 0;
border-radius: 0;
}
.jx-tgroup {
corner-shape: var(--corner-shape, bevel);
display: inline-flex;
width: fit-content;
flex-wrap: wrap;
overflow: hidden;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--card);
box-shadow: var(--shadow-2xs);
}
.jx-tgroup> label {
display: inline-flex;
align-items: center;
min-block-size: var(--jx-hit, 2.5rem);
padding-block: calc((var(--jx-hit, 2.5rem) - var(--jx-line, 1.25rem)) / 2);
padding-inline: var(--jx-inset, 0.75rem);
font-family: var(--font-nav);
font-size: var(--jx-text, 0.8125rem);
line-height: var(--jx-line, 1.25rem);
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted-foreground);
background-color: transparent;
border-inline-end: 1px solid var(--border);
cursor: pointer;
user-select: none;
transition: color 150ms ease-out, background-color 150ms ease-out;
}
.jx-tgroup> label:last-child {
border-inline-end: 0;
}
.jx-tgroup> label:not(:has(input:disabled)):hover {
color: var(--foreground);
}
.jx-tgroup> label:has(input:checked) {
background-color: var(--primary);
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:checked):not(:has(input:disabled)):hover {
color: var(--primary-foreground);
}
.jx-tgroup> label:has(input:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-tgroup> label:has(input:disabled) {
cursor: not-allowed;
opacity: 0.45;
}
.jx-tgroup> label > input {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.jx-tgroup[data-chrome='bare'] {
border: 0;
background: transparent;
box-shadow: none;
border-radius: 0;
overflow: visible;
}
.jx-tgroup[data-chrome='bare'] > label {
border-inline-end: 0;
flex: 1 1 auto;
justify-content: center;
}
.jx-tgroup[data-chrome='bare'] > label:not(:has(input:disabled)):hover {
color: var(--foreground);
background-color: color-mix(in oklab, var(--muted) 55%, transparent);
}
@media (prefers-reduced-motion: reduce) {
.jx-tgroup> label {
transition: none;
}
}
.jx-control {
box-sizing: border-box;
display: block;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding: var(--jx-gap, 0.5rem) var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font-size: var(--jx-text, 0.875rem);
color-scheme: light;
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control:focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
.jx-control:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.jx-control[aria-invalid='true'] {
border-style: dashed;
border-color: var(--error);
color: var(--error);
}
.jx-control[aria-invalid='false'] {
border-color: var(--primary);
}
.jx-control::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control[type='email'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search'] {
padding-inline-start: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
.jx-control {
transition: none;
}
}
.jx-control-shell {
box-sizing: border-box;
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
font-size: var(--jx-text, 0.875rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
box-shadow: var(--shadow-well);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
.jx-control-shell:has(> .jx-html-clear:last-child) {
padding-inline-end: 0;
}
.jx-control-shell:hover {
box-shadow: var(--shadow-well-hover);
}
.jx-control-shell:has(:focus) {
border-color: var(--ring);
}
.jx-control-shell:has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
.jx-control-shell:has([aria-invalid='true']), .jx-control-shell.jx-invalid {
border-style: dashed;
}
.jx-control-shell:has(:disabled) {
border-color: var(--muted);
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
.jx-control-shell {
transition: none;
}
}
.jx-control-lane {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
padding: 0;
outline: none;
background: transparent;
color: var(--foreground);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
}
.jx-control-lane::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
.jx-control-lane::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
.jx-control-lane[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
.jx-control-lane[type='email'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search'] {
padding-inline-start: calc(1.4em + var(--jx-gap, 0.5rem));
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left 0 center;
background-size: 1.4em;
background-repeat: no-repeat;
}
.jx-control-lane[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
/* @jixoai/css-laws:end:jx-html-alias */
.jx-control-shell.jx-slotted {
padding-inline: var(--jx-inset, 0.75rem);
}
.jx-control-shell .jx-control-lane {
padding-inline: 0;
}
.jx-field {
display: flex;
flex-direction: column;
gap: var(--jx-stack, 0.5rem);
width: 100%;
min-width: 0;
}
.jx-label {
font-family: var(--font-nav);
/* secondary-text is a density ROLE (density-adoption §3): the label
* tracks the ambient scope instead of a fixed 11px (2026-08-29) */
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
cursor: pointer;
}
.jx-error {
display: flex;
align-items: center;
gap: 0.25rem;
font-size: var(--jx-text-secondary, 11px);
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--destructive);
}
.jx-error-mark {
font-weight: bold;
}
/* the shell carries NO chrome itself (final-check ruling): the box
* chrome — border AND fill — lives on a ::before BAND whose height
* matches the -webkit-color-swatch-wrapper (the actual color chip's
* lane). 2026-08-29: the fill moved OFF the shell — an element-painted
* background leaks a full-height rectangle that ears out above/below
* the band on any surface where ambient ≠ --background (cards,
* panels, dark); the band now fills itself.
*
* GEOMETRY LAW (final-check ruling 2, the checkbox/range precedent):
* the chip is a LOCKED size-and-ratio block — height = the hit lane,
* aspect 7:4 (≈4.8rem at the 2.75rem hit — visually balanced, NOT a
* literal width), and the shell is its own SIZE CONTAINER: every
* internal geometry derives from 100cqh, so a density change (or a
* consumer height override) scales the whole chip proportionally —
* the swatch circle, the band, the pill radius, the glyph. The hit
* token sets ONLY the height; nothing else reads it. */
.jx-color-shell {
display: flex;
flex: none;
/* the shell's internal ladder (swatch z1, pipette ::after z2, the
custom-picker overlay z1) is COMPONENT-PRIVATE: container-type
does NOT establish a stacking context (measured, the isolation
clause 2026-09-09), so the shell roots it explicitly — the
deferred class-(a) tail cleared */
isolation: isolate;
/* fit-content protects the ratio-derived width from stretch (grid
tracks, block flow) while aspect-ratio + the locked height keep
it the chip's intrinsic 7:4 */
width: fit-content;
height: var(--jx-hit, 2.5rem);
aspect-ratio: 7 / 4;
container-type: size;
cursor: pointer;
position: relative;
transition: box-shadow 150ms ease-out;
}
.jx-color-shell::before {
content: '';
position: absolute;
inset-inline: 0;
inset-block: calc(100cqh / 6);
border: 1px solid var(--border);
background: var(--background);
pointer-events: none;
corner-left-shape: round;
/* band height = 100cqh − 2×(100cqh/6) = 100cqh × 2/3 — half of it
is the true-semicircle pill radius (no clamp hack) */
border-top-left-radius: calc(100cqh / 3);
border-bottom-left-radius: calc(100cqh / 3);
corner-right-shape: bevel;
/* the right radius rides the SAME cq quantum as the band inset
(100cqh/6 ≈ 8px at the default hit — was var(--radius, 8px),
which froze while every other edge scaled with the container;
B4: no internal dimension outside cq units) */
border-top-right-radius: calc(100cqh / 6);
border-bottom-right-radius: calc(100cqh / 6);
}
.jx-color-expand {
/* both dimensions definite → aspect-ratio yields; the chip keeps
its locked height across the full row.
FLEX PARTICIPATION is re-opened here on purpose: the base shell's
flex:none protects the COMPACT chip, but it also beats any layered
flex utility (this zone is unlayered) — so width:100% alone would
size against the WHOLE flex container and overflow any sibling
(the Tier-1 demo row, 2026-08-29: 77+12+329 > 329). grow reclaims
the full row, shrink shares it; block flow is untouched. */
width: 100%;
flex: 1 1 auto;
}
.jx-color-shell:has([aria-invalid='true'])::before,
.jx-color-shell.jx-invalid::before {
border-style: dashed;
}
.jx-color-shell .jx-color-swatch {
position: relative;
z-index: 1;
flex: none;
/* the chip lane = the container's full height; the swatch circle
inside sizes from the input's own padding (also cqh-relative) */
width: 100cqh;
height: auto;
align-self: stretch;
border: 0;
border-inline-end: 1px solid var(--border);
padding: calc(100cqh / 6);
}
.jx-color-shell .jx-color-swatch:focus-visible {
outline: none;
}
/* clear button: SUPERSEDED by jx-html-clear in the standard layer */
/* @jixoai/css-laws:begin:jx-icon-vocab — GENERATED, do not edit (source: packages/css-laws/src/icon-vocab) */
/* the pipette glyph — an ICON SLOT on the WRAPPER (input[type=color]
* is a replaced element whose ::after is unreliable across engines;
* the label wrapper is non-replaced and paints reliably) */
.jx-color-shell::after {
content: '';
position: absolute;
/* decorative carrier (the law's TRANSIENT INK family) + a ladder
rung — z2 orders against the swatch z1 INSIDE the shell, whose
own isolation: isolate roots the ladder (the isolation clause,
2026-09-09; the shell rule lives in the hand zone above) */
z-index: 2;
/* proportional optics: glyph ≈ 36% of the lane, end inset ≈ 27% —
scale with the container, not with font size */
inset-inline-end: calc(100cqh * 0.27);
top: 50%;
width: calc(100cqh * 0.36);
height: calc(100cqh * 0.36);
translate: 0 -50%;
color: var(--muted-foreground);
background-color: currentColor;
-webkit-mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-palette, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='13.5' cy='6.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='17.5' cy='10.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='8.5' cy='7.5' r='.5' fill='%23000' stroke='none'/%3E%3Ccircle cx='6.5' cy='12.5' r='.5' fill='%23000' stroke='none'/%3E%3Cpath d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z'/%3E%3C/svg%3E")) center / contain no-repeat;
pointer-events: none;
}
.jx-color-shell:hover::after {
color: var(--foreground);
}
/* the color-picker chevron — an ICON SLOT (mask, currentColor themes) */
.jx-color-picker-chevron {
display: block;
width: 0.75rem;
height: 0.75rem;
background-color: currentColor;
-webkit-mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
mask: var(--jx-icon-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")) center / contain no-repeat;
}
/* =====================================================================
Icon vocabulary — the mask/currentColor law. One alpha-only URI per
glyph; the encoded stroke %23000 is an ALPHA SOURCE ONLY. The INK
variants (calendar/clock/valid/invalid) serve UA-shadow pseudos that
reject author mask paint; .dark flips them to %23fff, .jx-light back.
===================================================================== */
@layer theme {
:root {
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* THEME-SCOPED placeholder (canvas bug, Owner 2026-09-04 — same law
as the variant-grammar slots in jixoai.css): custom properties
substitute their var() at the DECLARING element — a :root-only
--jx-placeholder handed every descendant the root's
already-substituted mix, so a scoped .dark/.jx-light
(component-canvas stage, terminal-card, print) flipping
--foreground/--background never re-flipped the placeholder ink
with it. The selector list re-declares the slot ON each theme
scope: one declaration point, zero duplicates */
:root,
.jx-light,
.dark {
--jx-placeholder: color-mix(in oklab, var(--foreground) 40%, var(--background));
}
}
.dark {
/* the author-painted icon set flips to white ink in dark (the
-ink quartet's law extended to the plain slots the input/select
laws consume — black alpha URIs vanish on the dark token sheet) */
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
.jx-light {
--jx-icon-mail: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E");
--jx-icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
--jx-icon-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
--jx-icon-clear: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
--jx-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-calendar-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
--jx-icon-clock-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
--jx-icon-valid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
--jx-icon-invalid-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E");
}
/* @jixoai/css-laws:end:jx-icon-vocab */
/* =====================================================================
The zero-class STRUCTURAL input group: a label wrapping a text-like
control AND at least one span composes into the shell — the label
takes the box law, the spans ride as prefix/suffix cells, the
control goes chromeless. NO opt-in class needed.
===================================================================== */
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) {
display: flex;
width: 100%;
min-height: var(--jx-hit, 2.5rem);
gap: var(--jx-gap, 0.5rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
padding-inline: var(--jx-inset, 0.75rem);
cursor: text;
transition: box-shadow 150ms ease-out;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):hover {
box-shadow: var(--shadow-2xs);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span):has(:focus-visible) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > span {
display: inline-flex;
align-items: center;
flex: none;
font-size: var(--jx-text, 0.875rem);
color: var(--muted-foreground);
}
:where(label:has(> input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
))):has(> span) > input {
flex: 1 1 auto;
min-height: calc(var(--jx-hit, 2.5rem) - 2px);
min-width: 0;
border: 0;
outline: none;
background: transparent;
color: var(--foreground);
font: inherit;
font-size: var(--jx-text, 0.875rem);
padding-inline: 0;
}
/* =====================================================================
Switch size modifiers (face-owned; the standard utility carries the
density-alias default, these opt into explicit sizes)
===================================================================== */
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-sm:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-sm input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 2rem;
--jx-toggle-track: 1.25rem;
--jx-toggle-knob: 0.75rem;
}
:where(.jx-pure) input[type='checkbox'][role='switch'].jx-switch-lg:not(.no-jx-pure, .no-jx-pure *),
.jx-pure .jx-switch-lg input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
--jx-toggle-width: 3rem;
--jx-toggle-track: 1.5rem;
--jx-toggle-knob: 1.25rem;
}
/* =====================================================================
Bare color input: the locked square standalone (without a .jx-color-
shell wrapper)
===================================================================== */
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: calc(var(--jx-hit, 2.5rem) - 2px);
padding: 2px;
}
/* =====================================================================
Reduced-motion law: the sheet's face-owned transitions neutralize.
===================================================================== */
@media (prefers-reduced-motion: reduce) {
.jx-control,
.jx-control-shell,
.jx-color-shell {
transition: none;
}
}
/* =====================================================================
B · ELEMENT DEFAULTS — the .jx-pure subtree face.
Every rule rides :where(.jx-pure) so the scope class contributes
ZERO specificity inside @layer components: Tailwind utilities
(utilities layer) and any unlayered author css override these
cheaply, and non-Tailwind static consumers override with plain
css. Colors come from tokens or currentColor ONLY — no hardcoded
paint survives a theme flip.
===================================================================== */
@layer components {
/* ---- B0 · the scope root: color-scheme follows the theme classes
the token sheet owns. color-scheme INHERITS — one declaration
themes every native picker, scrollbar and form control in the
subtree: light under :root, dark under .dark (ancestor or self),
forced light under .jx-light. */
:where(.jx-pure):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
/* density adoption (native-contract-fusion Phase 5): the scope
root rides the density interface's text/leading aliases (the
typography LADDER above keeps its fixed steps — declared gap) */
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.6);
}
:where(.dark) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.dark):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
:where(.jx-light) :where(.jx-pure):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure.jx-light):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: light;
}
/* =====================================================================
B1 · Typography — documented rem steps (the repo ships no
typography size tokens; these literals ARE the scale until a
token ruling lands — do not scatter new sizes elsewhere). The
flow margins are EXPLICIT because preflight zeroes them: a
Tailwind host without this block would render wall-of-text prose.
===================================================================== */
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6):not(.no-jx-pure, .no-jx-pure *) {
margin: 1.5em 0 0.6em;
font-weight: 700;
line-height: 1.25;
color: var(--foreground);
}
:where(.jx-pure) h1:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.875rem;
}
:where(.jx-pure) h2:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.5rem;
}
:where(.jx-pure) h3:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.25rem;
}
:where(.jx-pure) h4:not(.no-jx-pure, .no-jx-pure *) {
font-size: 1.125rem;
}
:where(.jx-pure) :where(h5, h6):not(.no-jx-pure, .no-jx-pure *) {
font-size: 1rem;
}
:where(.jx-pure) :where(p, ul, ol, dl, blockquote, pre, table, hr):not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
}
:where(.jx-pure) p:not(.no-jx-pure, .no-jx-pure *) {
line-height: 1.6;
}
:where(.jx-pure) :where(h1, h2, h3, h4, h5, h6) :where(p, ul, ol, dl, blockquote, pre, table):first-child:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0;
}
:where(.jx-pure) small:not(.no-jx-pure, .no-jx-pure *) {
font-size: 0.8125rem;
color: var(--muted-foreground);
}
:where(.jx-pure) :where(strong, b):not(.no-jx-pure, .no-jx-pure *) {
font-weight: 700;
}
:where(.jx-pure) blockquote:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-start: 0.875rem;
border-inline-start: 1px solid var(--border);
color: var(--muted-foreground);
}
:where(.jx-pure) :where(code, kbd, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.1em 0.4em;
border: 1px solid var(--border);
background: var(--muted);
font-family: var(--font-mono);
font-size: 0.8125rem;
}
:where(.jx-pure) kbd:not(.no-jx-pure, .no-jx-pure *) {
/* the key cap is ENGRAVED, not lifted (F-2, adversarial-review
2026-09-02 — Owner kbd ruling): --shadow-engrave inset, the
elevation grammar's engrave tier, unified with the registry kbd
component (shadow-engrave). The old `0 1px 0 var(--border)`
lifted-edge dialect is retired — one kbd face across the bare
element and the component. */
box-shadow: var(--shadow-engrave);
}
:where(.jx-pure) pre:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.75rem 1rem;
border: 1px solid var(--border);
background: var(--background);
overflow: auto;
font-family: var(--font-mono);
font-size: 0.8125rem;
line-height: 1.55;
}
/* the code-in-pre lane drops its inline box — the pre owns the box */
:where(.jx-pure) pre :where(code, samp):not(.no-jx-pure, .no-jx-pure *) {
padding: 0;
border: 0;
background: transparent;
font-size: inherit;
}
:where(.jx-pure) mark:not(.no-jx-pure, .no-jx-pure *) {
padding: 0.05em 0.25em;
background: color-mix(in oklab, var(--secondary) 45%, var(--background));
color: var(--foreground);
}
:where(.jx-pure) hr:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 1.5rem;
border: 0;
border-top: 1px solid var(--border);
}
/* =====================================================================
B2 · Links — the site link law (press-button link variant):
primary text, no underline at rest, underline on hover. Nav links
read as chrome, not prose: foreground at rest, primary + underline
as the hover cue.
===================================================================== */
:where(.jx-pure) a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-underline-offset: 4px;
}
:where(.jx-pure) a:hover:not(.no-jx-pure, .no-jx-pure *) {
text-decoration-line: underline;
}
:where(.jx-pure) nav a:not(.no-jx-pure, .no-jx-pure *) {
color: var(--foreground);
}
:where(.jx-pure) nav a:hover:not(.no-jx-pure, .no-jx-pure *) {
color: var(--primary);
text-decoration-line: underline;
}
/* =====================================================================
B3 · Buttons — the .jx-press physics restated element-scoped
(hover grows the token shadow + bg-muted; active presses +1px
into the page with the *-press twin — same variable contract,
no WAAPI, no second geometry law). .jx-button is the EXPLICIT
channel for link-look buttons (Codex D2: never auto-style
a[role=button] — CSS cannot add command semantics). Focus is
deliberately NOT set here: the host's focus law owns it (site
base layer paints a/button; static pages keep the UA ring).
===================================================================== */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *) {
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.375rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 1rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
line-height: 1.45;
text-decoration: none;
cursor: pointer;
box-shadow: var(--jx-press-shadow, var(--shadow-xs));
transition:
translate 150ms ease-out,
box-shadow 150ms ease-out,
background-color 150ms ease-out,
border-color 150ms ease-out,
color 150ms ease-out;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):hover:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
box-shadow: var(--jx-press-shadow-hover, var(--shadow-sm));
}
/* :active LAST — at equal specificity the later rule wins the hover pose */
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: 1px 1px;
box-shadow: var(--jx-press-shadow-active, var(--shadow-sm-press));
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
cursor: not-allowed;
box-shadow: none;
}
/* =====================================================================
B4+B5 · form controls = @apply applications of the standard
layer (the 13-type allowlist rides each selector; the number lane
keeps the PLATFORM stepper by sharing jx-html-input; checkbox
excludes [role=switch] so the switch gets its own utility) ----- */
/* GENERATED between the markers (css-laws V3): the bare-element
defaults — same declaration source as the .jx-html-* classes,
serialized as element-default rules under :where(.jx-pure) */
/* @jixoai/css-laws:begin:jx-html-face — GENERATED, do not edit (source: packages/css-laws/src/laws) */
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where(:not([type]), [type='text'], [type='password'], [type='email'], [type='url'], [type='tel'], [type='search'], [type='date'], [type='time'], [type='datetime-local'], [type='month'], [type='week'], [type='number']):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-textarea-min, 5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
height: auto;
resize: vertical;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) textarea:where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
--jx-icon-chevron-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
corner-shape: var(--corner-shape, bevel);
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
box-shadow: var(--shadow-well);
caret-color: var(--primary);
font: inherit;
font-size: var(--jx-text, 0.875rem);
line-height: var(--jx-leading, 1.45);
transition: box-shadow 150ms ease-out, border-color 150ms ease-out;
cursor: pointer;
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::placeholder, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::placeholder {
color: var(--jx-placeholder, color-mix(in oklab, var(--foreground) 40%, var(--background)));
opacity: 1;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
box-shadow: var(--shadow-well-hover);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
border-color: var(--ring);
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):disabled, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))::-webkit-calendar-picker-indicator {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-calendar, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='time']::-webkit-calendar-picker-indicator {
background-image: var(--jx-icon-clock, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"));
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='email'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='email'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-mail, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='16' x='2' y='4' rx='2'/%3E%3Cpath d='m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search'], :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search'] {
padding-inline: calc(var(--jx-inset, 0.75rem) + 1.4em + var(--jx-gap, 0.5rem)) var(--jx-inset, 0.75rem);
background-image: var(--jx-icon-search, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E"));
background-position: left var(--jx-inset, 0.75rem) center;
background-size: 1.4em;
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button, :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *))[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
width: 1.4em;
height: 1.4em;
margin-inline-start: var(--jx-gap, 0.5rem);
cursor: pointer;
background-image: var(--jx-icon-clear, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"));
background-size: contain;
background-repeat: no-repeat;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
}
@supports not selector(::-moz-range-progress) {
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
background-image: var(--jx-icon-chevron, var(--jx-icon-chevron-svg));
background-position: right var(--jx-inset, 0.75rem) center;
background-size: var(--jx-icon, 1.25rem);
background-repeat: no-repeat;
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):hover:not(:disabled) {
filter: none;
}
}
:where(.jx-pure) select:where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]), :where(.jx-pure) select:where([multiple], [size]):where(:not(.no-jx-pure, .no-jx-pure *)):where([multiple], [size]) {
min-height: 5.75rem;
padding-block: 0.375rem 0.5rem;
cursor: default;
background-image: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
cursor: pointer;
transition: background-color 150ms ease-out, border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate::before {
opacity: 1;
transform: rotate(0deg);
clip-path: polygon(10% 40%, 10% 60%, 45% 60%, 55% 60%, 90% 60%, 90% 40%);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):checked, :where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):indeterminate {
background: var(--primary);
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox']:not([role='switch']):not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
position: relative;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-icon, 1.25rem);
height: var(--jx-icon, 1.25rem);
margin: 0;
flex: none;
border: 1px solid var(--border);
border-radius: 50%;
background: var(--background);
cursor: pointer;
transition: border-color 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
content: none;
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
background: var(--primary-foreground);
opacity: 0;
transform: rotate(45deg);
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 80%, 70% 80%, 70% 100%);
transition: clip-path 150ms ease-out, opacity 150ms ease-out, transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
opacity: 1;
clip-path: polygon(20% 100%, 20% 80%, 50% 80%, 50% 0%, 70% 0%, 70% 100%);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::after {
content: '';
position: absolute;
inset: 2px;
display: block;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
border-radius: 50%;
background: var(--primary);
transform: scale(0);
transition: transform 150ms ease-out;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked::after {
transform: scale(1);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
border-color: var(--primary);
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))[aria-invalid='true'] {
border-style: dashed;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--background);
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='radio']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
position: relative;
width: var(--jx-toggle-width, 2.5rem);
height: var(--jx-toggle-track, 1.5rem);
margin: 0;
flex: none;
padding: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
border: 0;
box-shadow: 0 0 0 1px var(--border) inset;
border-radius: calc(infinity * 1px);
background: var(--muted);
cursor: pointer;
transition: background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
content: '';
position: absolute;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
inset-block: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inset-inline-start: calc((var(--jx-toggle-track, 1.5rem) - var(--jx-toggle-knob, 1rem)) / 2 - var(--jx-toggle-knob-border, 1px));
inline-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
block-size: calc(var(--jx-toggle-knob, 1rem) + 2 * var(--jx-toggle-knob-border, 1px));
border-radius: calc(infinity * 1px);
border: var(--jx-toggle-knob-border, 1px) solid var(--jx-toggle-knob-border-color, var(--primary));
background: var(--background);
transform: translateX(0);
transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1), background-color 200ms cubic-bezier(0.22, 1, 0.36, 1), border-color 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked::before {
transform: translateX(calc(var(--jx-toggle-width, 2.5rem) - var(--jx-toggle-track, 1.5rem)));
background: var(--primary-foreground);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):hover:not(:checked):not(:disabled) {
box-shadow: 0 0 0 1px var(--primary) inset;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):checked {
background: var(--primary);
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *)) {
transition: none;
}
:where(.jx-pure) input:where([type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *))::before {
transition: none;
}
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)) {
--jx-range-thumb: 100cqh;
--jx-range-track: calc(100cqh / 2.5);
--jx-range-ring: calc(100cqh / 8);
--jx-slider-fill-color: var(--primary);
--jx-range-length: calc(var(--jx-unit, 0.25rem) * 40);
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
display: block;
width: 100%;
height: var(--jx-icon, 1.5rem);
margin: 0;
border: 0;
border-radius: calc(infinity * 1px);
background: transparent;
container-type: size;
overflow: hidden;
cursor: pointer;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-runnable-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
margin-top: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
box-shadow: calc(-100cqw - var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):dir(rtl)::-webkit-slider-thumb {
box-shadow: calc(100cqw + var(--jx-range-thumb) / 2) 0 0 100cqw var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"] {
--jx-range-thumb: 100cqw;
--jx-range-track: calc(100cqw / 2.5);
--jx-range-ring: calc(100cqw / 8);
writing-mode: vertical-lr;
direction: rtl;
width: var(--jx-icon, 1.5rem);
height: var(--jx-range-length);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-runnable-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-webkit-slider-thumb {
margin-top: 0;
margin-left: calc((var(--jx-range-track) - var(--jx-range-thumb)) / 2);
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]:dir(rtl)::-webkit-slider-thumb {
box-shadow: 0 calc(100cqh + var(--jx-range-thumb) / 2) 0 100cqh var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-track {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))[orient="vertical"]::-moz-range-progress {
width: var(--jx-range-track);
height: auto;
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-track {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--muted);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-progress {
height: var(--jx-range-track);
border-radius: calc(infinity * 1px);
background: var(--jx-slider-fill-color);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *))::-moz-range-thumb {
box-sizing: border-box;
corner-shape: var(--corner-shape, bevel);
width: var(--jx-range-thumb);
height: var(--jx-range-thumb);
border-radius: 50%;
border: var(--jx-range-ring) solid var(--primary);
background: var(--background);
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):focus-visible {
outline: 1px solid var(--ring);
outline-offset: 2px;
}
:where(.jx-pure) input:where([type='range']:not(.no-jx-pure, .no-jx-pure *)):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *)) {
appearance: none;
-webkit-appearance: none;
box-sizing: border-box;
width: calc(var(--jx-hit, 2.5rem) - 2px);
height: auto;
align-self: stretch;
flex: none;
padding: calc(var(--jx-hit, 2.5rem) / 6);
border: 1px solid var(--border);
border-radius: 50%;
corner-shape: round;
background: conic-gradient(from 0deg, #ff0000 0deg, #ffff00 60deg, #00ff00 120deg, #00ffff 180deg, #0000ff 240deg, #ff00ff 300deg, #ff0000 360deg);
cursor: pointer;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch-wrapper {
padding: 0;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-webkit-color-swatch {
border: 2px solid #FFF;
border-radius: 50%;
corner-shape: round;
}
:where(.jx-pure) input:where([type='color']:not(.no-jx-pure, .no-jx-pure *))::-moz-color-swatch {
border: 0;
border-radius: 0;
}
/* @jixoai/css-laws:end:jx-html-face */
/* ---- B6 · label / fieldset / legend (face-owned; not form-
control law — the one-opacity-owner disabled law) -------------
===================================================================== */
:where(.jx-pure) label:not(.no-jx-pure, .no-jx-pure *) {
cursor: pointer;
}
:where(.jx-pure) fieldset:not(.no-jx-pure, .no-jx-pure *) {
min-width: 0;
margin-block: 0.75rem;
padding: 0.875rem 1rem 1rem;
border: 1px solid var(--border);
border-radius: 0;
}
:where(.jx-pure) fieldset:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* ONE opacity owner per subtree (Codex review A3): the group dims to
.5 and the controls inside stay at 1 — two stacked .5 layers
composite to ~.25 and the contrast collapses */
:where(.jx-pure) fieldset:disabled :where(input, textarea, select, button):not(.no-jx-pure, .no-jx-pure *) {
opacity: 1;
cursor: not-allowed;
}
:where(.jx-pure) legend:not(.no-jx-pure, .no-jx-pure *) {
padding-inline: 0.5rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* =====================================================================
B7 · details / summary — document-flow disclosure ONLY (dialog /
popover / tooltip stay Tier-2, Codex D3). Static marker swap, no
open/close animation (progressive enhancement deferred); the
visible focus ring is never replaced by the marker.
===================================================================== */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *) {
display: flex;
align-items: center;
gap: 0.625rem;
min-height: var(--jx-hit, 2.5rem);
padding-block: var(--jx-gap, 0.5rem);
padding-inline: var(--jx-inset, 0.75rem);
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--foreground);
font: inherit;
font-size: 0.875rem;
list-style: none;
cursor: pointer;
transition:
border-color 150ms ease-out,
box-shadow 150ms ease-out;
}
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::-webkit-details-marker {
display: none;
}
/* the marker: a bordered square holding + / − (static swap) */
:where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '+';
box-sizing: border-box;
display: grid;
place-items: center;
width: 1.125rem;
height: 1.125rem;
flex: none;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
color: var(--muted-foreground);
font-family: var(--font-nav);
font-size: 12px;
line-height: 1;
}
:where(.jx-pure) details[open] > summary:not(.no-jx-pure, .no-jx-pure *)::before {
content: '−';
}
:where(.jx-pure) summary:hover:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--primary); /* leans like the checkbox border */
}
:where(.jx-pure) summary:focus-visible:not(.no-jx-pure, .no-jx-pure *) {
outline: 1px solid var(--ring);
outline-offset: -1px;
}
:where(.jx-pure) details > * + *:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.5rem;
}
/* =====================================================================
B8 · lists / dl — restore the document-flow markers preflight
removes (classless parity) and theme them; nav's link law lives
in B2.
===================================================================== */
:where(.jx-pure) ul:not(.no-jx-pure, .no-jx-pure *) {
list-style: disc;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) ol:not(.no-jx-pure, .no-jx-pure *) {
list-style: decimal;
padding-inline-start: 1.5rem;
}
:where(.jx-pure) li:not(.no-jx-pure, .no-jx-pure *)::marker {
color: var(--muted-foreground);
}
:where(.jx-pure) dl:not(.no-jx-pure, .no-jx-pure *) {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.375rem 1rem;
}
:where(.jx-pure) dt:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
:where(.jx-pure) dd:not(.no-jx-pure, .no-jx-pure *) {
margin: 0;
}
/* =====================================================================
B9 · Tables — the bordered grid law.
===================================================================== */
:where(.jx-pure) table:not(.no-jx-pure, .no-jx-pure *) {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
:where(.jx-pure) caption:not(.no-jx-pure, .no-jx-pure *) {
margin-block-start: 0.375rem;
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
caption-side: bottom;
text-align: start;
}
:where(.jx-pure) :where(th, td):not(.no-jx-pure, .no-jx-pure *) {
padding: 0.5rem 0.75rem;
border: 1px solid var(--border);
text-align: start;
}
:where(.jx-pure) th:not(.no-jx-pure, .no-jx-pure *) {
background: var(--muted);
font-family: var(--font-nav);
font-size: 11px;
font-weight: 400;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
white-space: nowrap;
}
:where(.jx-pure) tbody tr:hover:not(.no-jx-pure, .no-jx-pure *) {
background: color-mix(in oklab, var(--muted) 26%, transparent);
}
/* =====================================================================
B10 · progress / meter / output (Owner completion round, 2026-08-24:
the Codex D6 deferral is overruled — the contracts exist now).
progress: the range-track geometry (8px bordered box, primary
fill); indeterminate trades the fill for a sliding stripe, fully
static under reduced motion. meter: the same box with the
SEMANTIC token mapping — optimum=primary, suboptimal=secondary,
even-less-good=destructive (no hardcoded traffic lights). output:
the mono result lane. Engine pseudos live in SEPARATE rules (the
R1 law: a shared -moz list is dropped whole by Chromium).
===================================================================== */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *) {
display: block;
box-sizing: border-box;
width: 100%;
height: 0.5rem; /* the 8px track family (incl. borders) */
margin: 0;
border: 1px solid var(--border);
border-radius: 0;
background: var(--background);
appearance: none;
-webkit-appearance: none;
overflow: hidden;
}
:where(.jx-pure) progress:disabled:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) meter:disabled:not(.no-jx-pure, .no-jx-pure *) {
opacity: 0.5;
}
/* chromium: the track pseudo + the value pseudo */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-bar {
background: var(--background);
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-webkit-progress-value {
background: var(--primary);
transition: width 150ms ease-out;
}
/* indeterminate: no percent exists — a muted stripe slides across.
The stripe rides the ELEMENT's own background, never the UA
pseudos: engines reject author paint/animation on progress
pseudos exactly like the number spinners (Codex r4 R4-1 — the
pseudo path compiled but never animated). Part C parks it under
reduced motion. */
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *) {
background:
linear-gradient(in oklab, var(--muted), var(--muted)) 0 0 / 40% 100% no-repeat,
var(--background);
animation: jx-progress-slide 1.2s linear infinite;
}
/* firefox: the element is the track; the bar pseudo is the value */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: var(--primary);
}
:where(.jx-pure) progress:indeterminate:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
background: transparent; /* the element's stripe owns the paint */
}
/* meter: the semantic three-state fill (token-mapped, monochrome law) */
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-bar {
background: var(--background);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-optimum-value {
background: var(--primary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-suboptimum-value {
background: var(--secondary);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-webkit-meter-even-less-good-value {
background: var(--destructive);
}
:where(.jx-pure) meter:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--primary);
}
:where(.jx-pure) meter:-moz-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--secondary);
}
:where(.jx-pure) meter:-moz-sub-sub-optimum:not(.no-jx-pure, .no-jx-pure *)::-moz-meter-bar {
background: var(--destructive);
}
/* the stripe keyframes live OUTSIDE the layer's rule bodies… they
are defined once here (keyframes are global; the jx- prefix keeps
the namespace) — declared at the layer's end so both engine rules
above can reference them */
}
@keyframes jx-progress-slide {
from {
background-position: -40% 0, 0 0;
}
to {
background-position: 140% 0, 0 0;
}
}
@layer components {
/* output: the calculation result lane — mono, foreground, inline */
:where(.jx-pure) output:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-mono);
font-size: 0.875rem;
color: var(--foreground);
}
/* =====================================================================
B11 · figure / media — the documentation flow. figure carries the
flow margin + the bordered plate; figcaption rides the caption
law (nav font, small caps, muted, below). Media never overflows
its lane.
===================================================================== */
:where(.jx-pure) :where(img, video):not(.no-jx-pure, .no-jx-pure *) {
max-width: 100%;
height: auto;
}
:where(.jx-pure) figure:not(.no-jx-pure, .no-jx-pure *) {
margin-block: 0.75rem;
display: flex;
flex-direction: column;
gap: 0.375rem;
max-width: 100%;
}
:where(.jx-pure) figure > :where(img, video, svg, pre, table):not(.no-jx-pure, .no-jx-pure *) {
border: 1px solid var(--border);
}
:where(.jx-pure) figcaption:not(.no-jx-pure, .no-jx-pure *) {
font-family: var(--font-nav);
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted-foreground);
}
/* ---- B13 · switch = @apply application (the ONE input law;
[role=switch] discriminates it from the checkbox) ------------- */
/* the label posture: a wrapping label dims with its input */
:where(.jx-pure) label:has(> input[type='checkbox'][role='switch']):not(.no-jx-pure, .no-jx-pure *) {
display: inline-flex;
align-items: center;
gap: var(--jx-gap, 0.5rem);
cursor: pointer;
user-select: none;
min-block-size: var(--jx-hit, 2.5rem);
&:has(input:disabled) {
cursor: not-allowed;
opacity: 0.5;
}
}
/* =====================================================================
B14 · validation states — the Pico state matrix on the SEMANTIC
palette (openspec D5): aria-invalid='false' leans --success ('✓'
ink + success border + success hover lean); aria-invalid='true'
flips every accent to --error (dashed lanes + '!' ink, checked
fills, the radio DOT, switch track, range fill + thumb).
--destructive is NOT used here — it stays the monochrome
inversion pair for destructive actions. Native :invalid stays
deliberately unhooked (no empty-required surprises).
===================================================================== */
/* lanes: border-color states + the ink glyphs */
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success);
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='true']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: calc(var(--jx-inset, 0.75rem) + var(--jx-icon, 1.25rem));
background-image: var(--jx-icon-invalid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
:where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number']
)[aria-invalid='false']:not(select):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) textarea[aria-invalid='false']:not(.no-jx-pure, .no-jx-pure *) {
padding-inline-end: 2rem;
background-image: var(--jx-icon-valid-ink);
background-position: right 0.625rem center;
background-size: 0.75rem 0.75rem;
background-repeat: no-repeat;
}
/* checkbox / radio: the checked accent flips to error */
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='checkbox'][aria-invalid='true']:indeterminate:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='radio'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::after {
background: var(--error-foreground);
}
:where(.jx-pure) input[type='checkbox'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio'][aria-invalid='false']:hover:not(:checked):not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--success); /* the valid lean */
}
/* switch: the checked track flips */
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *) {
background: var(--error);
border-color: var(--error);
}
:where(.jx-pure) input[type='checkbox'][role='switch'][aria-invalid='true']:checked:not(.no-jx-pure, .no-jx-pure *)::before {
border-color: transparent;
}
/* range: fill + thumb flip */
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *) {
--jx-slider-fill-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-webkit-slider-thumb {
border-color: var(--error);
}
:where(.jx-pure) input[type='range'][aria-invalid='true']:not(.no-jx-pure, .no-jx-pure *)::-moz-range-thumb {
background: var(--error);
}
}
/* =====================================================================
B12 · the reverse scope — .no-jx-pure (Owner third revision,
2026-08-24): the r8/r9 `all: revert !important` hatch was too
violent — it also rolled back the HOST's own utilities and inline
styles. Every face rule now carries the exclusion on its subject:
:not(.no-jx-pure, .no-jx-pure *) — an element that IS, or lives
inside, a no-jx-pure subtree never receives the face; everything
the host authored there is untouched. Part A opt-in classes still
work inside islands (author intent, not face paint). INHERITED
properties (color-scheme, custom property tokens) keep flowing
through islands from ancestors — the exclusion is element-level
paint, never a war against the page's theme or the host.
=====================================================================
*/
/* =====================================================================
C · DEGRADATION LAWS — motion and forced colors.
===================================================================== */
/* Reduced motion: FULL STILLNESS, not zero-duration animation (Codex
review B): every Part B transition goes none AND the interactive
displacements (the press translate, the thumb press transform) are
pinned back to their rest poses so nothing ever moves. */
@media (prefers-reduced-motion: reduce) {
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) input:where(
:not([type]),
[type='text'],
[type='password'],
[type='email'],
[type='url'],
[type='tel'],
[type='search'],
[type='number'],
[type='date'],
[type='time'],
[type='datetime-local'],
[type='month'],
[type='week']
):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) :where(textarea, select):not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *), :where(.jx-pure) summary:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
/* engine pseudos NEVER share a selector list — a non-forgiving list
with an unknown -moz pseudo is dropped WHOLE by Chromium (Codex
r2 R1); one rule per engine surface */
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
/* the indeterminate stripe parks: element animation off (the
authored -moz pseudo animation is likewise killed — one rule per
surface, and the -moz one stands alone) */
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *) {
animation: none;
}
:where(.jx-pure) progress:not(.no-jx-pure, .no-jx-pure *)::-moz-progress-bar {
animation: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before {
transition: none;
}
:where(.jx-pure) input[type='checkbox'][role='switch']:not(.no-jx-pure, .no-jx-pure *) {
transition: none;
}
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
transition: none;
}
:where(.jx-pure) :where(button, input:where([type='button'], [type='submit'], [type='reset']), .jx-button):active:not(:disabled):not(.no-jx-pure, .no-jx-pure *) {
translate: none;
}
}
/* Forced colors (Windows High Contrast & friends): the custom-painted
controls revert to appearance:auto so the SYSTEM palette and glyphs
speak — author paint would flatten into the forced canvas and lose
the checked/unchecked distinction entirely. Box laws (borders,
outlines) survive: forced-colors keeps author borders as system
colors. The opt-in select ALSO drops its gradient chevron or the
restored platform arrow would double up with the leftover paint. */
@media (forced-colors: active) {
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='range']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) input[type='color']:not(.no-jx-pure, .no-jx-pure *),
:where(.jx-pure) select:not(.no-jx-pure, .no-jx-pure *) {
appearance: auto;
-webkit-appearance: auto;
background-image: none;
}
:where(.jx-pure) input[type='checkbox']:not(.no-jx-pure, .no-jx-pure *)::before,
:where(.jx-pure) input[type='radio']:not(.no-jx-pure, .no-jx-pure *)::after {
content: none;
}
}
/* ==== BEGIN GENERATED · jx-auto-dark — scripts/gen-jx-auto-dark.mjs (do not hand-edit) ==== */
/* Derived 1:1 from jixoai.css's .dark block (single source). The gate
rides :where() so the whole variant stays maximally overridable; it
never fires where an explicit .dark already owns the theme, nor
inside .jx-light islands. Mount: <html class="jx-pure jx-auto-dark"> */
@media (prefers-color-scheme: dark) {
:where(.jx-auto-dark):not(.dark, .jx-light *) {
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--terminal: oklch(0.2 0 0);
--terminal-foreground: oklch(1 0 0);
--terminal-hover: color-mix(in oklab, var(--terminal-foreground) 14%, var(--terminal));
--terminal-muted: color-mix(in oklab, var(--terminal-foreground) 8%, var(--terminal));
--card: oklch(0.3211 0 0);
--card-foreground: oklch(1 0 0);
--popover: oklch(0.3211 0 0);
--popover-foreground: oklch(1 0 0);
/* the primary hue drifts -4° toward dark, mirroring the reference */
--primary: oklch(0.7044 0.1872 calc(var(--brand-hue) - 4));
--primary-foreground: oklch(0 0 0);
--primary-text: var(--primary);
--secondary: oklch(0.9691 0.2005 109.6228);
--secondary-foreground: oklch(0 0 0);
--muted: oklch(0.2178 0 0);
--muted-foreground: oklch(0.8452 0 0);
--accent: oklch(0.6755 0.1765 252.2592);
--accent-foreground: oklch(0 0 0);
--destructive: oklch(1 0 0);
--destructive-foreground: oklch(0 0 0);
--border: oklch(1 0 0);
--input: oklch(1 0 0);
--ring: var(--primary);
--success: oklch(0.72 0.16 145);
--success-foreground: oklch(0 0 0);
--warning: oklch(0.78 0.17 85);
--warning-foreground: oklch(0 0 0);
--info: oklch(0.74 0.14 245);
--info-foreground: oklch(0 0 0);
--error: oklch(0.72 0.16 25);
--error-foreground: oklch(0 0 0);
--chart-1: var(--primary);
--chart-2: var(--success);
--chart-3: var(--info);
--chart-4: var(--warning);
--chart-5: var(--error);
--shadow-color: hsl(0 0% 100%);
/* shadow GEOMETRY rides the light baseline rung for rung (Owner ruling,
2026-09-01: sizes must not drift between themes — only the INK
inverts to white; the old 4px-everywhere small rungs were copy-paste
drift, not design) */
--shadow-2xs: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-xs: 2px 2px 0px 0px hsl(0 0% 100% / 0.5);
/* ink compensation (F-11, 2026-09-02): the second layer's alpha is
deliberately NOT mirrored (0.5 light / 1.0 dark) — the black ring
rides directly on the white offset over a black ground, where
half-alpha would read as a gray smear; geometry stays rung for
rung, only the ink density compensates */
--shadow-sm: 2px 2px 0px 0px hsl(0 0% 100% / 1), 1px 1px 0px 1px hsl(0 0% 0% / 1);
--shadow: 4px 4px 0px 0px hsl(0 0% 100% / 1);
--shadow-md: 4px 4px 0px 0px hsl(0 0% 100% / 1), 4px 2px 4px -1px hsl(0 0% 0% / 1);
/* --shadow-lg removed with the light block (F-10) */
/* press poses — same minus-1px law as the light block above */
--shadow-xs-press: 1px 1px 0px 0px hsl(0 0% 100% / 0.5);
--shadow-sm-press: 1px 1px 0px 0px hsl(0 0% 100% / 1), 0px 0px 0px 1px hsl(0 0% 0% / 1);
--shadow-md-press: 3px 3px 0px 0px hsl(0 0% 100% / 1), 3px 1px 4px -1px hsl(0 0% 0% / 1);
/* elevation grammar, dark side: same geometry rung for rung, the
ink inverted to white (the white-shadow law); --shadow-paper is
theme-INDEPENDENT (paper stays white — see the light block).
The engrave duet inverts BOTH inks (the law's mechanical face —
the glow wall's black on dark reads as the carved sheen) */
--jx-engrave-shade: hsl(0 0% 100% / 0.4);
--jx-engrave-glow: hsl(0 0% 0% / 0.96);
--shadow-engrave: inset 1px 1px 0px 0px var(--jx-engrave-shade),
inset -1px -1px 0px 0px var(--jx-engrave-glow);
--shadow-well: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--shadow-well-hover: inset 1px 1px 0px 0px hsl(0 0% 100% / 0.28);
/* floating-surface law, dark side: inverted — scrims and the shadow
layer are semi-transparent WHITE and BRIGHTEN (the white-shadow
law; same 0.32 veil strength as light mode's black) */
--scrim: hsl(0 0% 100% / 0.1);
--surface-shadow: oklch(0 0 0 / 0.32); /* black — r14-17, Owner */
/* ── the surface ladder, dark side (explicit-props §7 / task 1.1):
the M3 dark law — shadows are weak here, the STEPS carry the
hierarchy; the rungs LIGHTEN upward, away from the page void,
and stay below --card (0.3211 — the existing panel tokens keep
their place above the ladder). 减色墨律: role steps, never
overlays. This block feeds the generated prefers-color-scheme
projection in jx-pure.css (gen-jx-auto-dark — single source). */
--surface: var(--background);
--surface-container-lowest: oklch(0.115 0 0);
--surface-container-low: oklch(0.185 0 0);
--surface-container: oklch(0.205 0 0);
--surface-container-high: oklch(0.245 0 0);
--surface-container-highest: oklch(0.29 0 0);
--surface-concave: var(--background);
/* ── the elevation level table, dark side (explicit-props §0.1/§7 /
task 1.2): geometry pinned rung for rung with light (the
2026-09-01 law — sizes never drift between themes), the ink
inverted to white at reduced alpha — the soft-lens compensation
(dark hierarchy rides the LADDER; full-alpha white glow through
a 12px blur would wash it). level-1 keeps the inset duet's
single shade wall at the well-tier strength. */
--jx-elevation-level-1-shadow:
inset 1px 1px 0px 0px hsl(0 0% 100% / 0.12);
--jx-elevation-level-1-surface: var(--surface-concave);
--jx-elevation-level0-shadow: none;
--jx-elevation-level0-surface: var(--surface);
--jx-elevation-level1-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 1px 3px 1px hsl(0 0% 100% / 0.08);
--jx-elevation-level1-surface: var(--surface-container-lowest);
--jx-elevation-level2-shadow:
0px 1px 2px 0px hsl(0 0% 100% / 0.16),
0px 2px 6px 2px hsl(0 0% 100% / 0.08);
--jx-elevation-level2-surface: var(--surface-container-low);
--jx-elevation-level3-shadow:
0px 1px 3px 0px hsl(0 0% 100% / 0.16),
0px 4px 8px 3px hsl(0 0% 100% / 0.08);
--jx-elevation-level3-surface: var(--surface-container);
--jx-elevation-level4-shadow:
0px 2px 3px 0px hsl(0 0% 100% / 0.16),
0px 6px 10px 4px hsl(0 0% 100% / 0.08);
--jx-elevation-level4-surface: var(--surface-container-high);
--jx-elevation-level5-shadow:
0px 4px 4px 0px hsl(0 0% 100% / 0.16),
0px 8px 12px 6px hsl(0 0% 100% / 0.08);
--jx-elevation-level5-surface: var(--surface-container-highest);
/* the color axis' effective carrier — dark's own --primary (the
hue-drifted one; re-declared per theme scope, the canvas-bug
law) */
--jx-color-effective: var(--primary);
color-scheme: dark;
}
/* the scope-root companion: without it B0's color-scheme: light would
out-shout the inherited root scheme and native pickers/scrollbars
would stay light under dark tokens (the inverted-A2 bug) */
:where(.jx-auto-dark) :where(.jx-pure):not(.jx-light, .jx-light *):not(.no-jx-pure, .no-jx-pure *) {
color-scheme: dark;
}
}
/* ==== END GENERATED · jx-auto-dark ==== */
System-follow, still zero JS — .jx-auto-dark
The zero-JS answer to OS-following dark: mount jx-auto-dark next to the scope class and Part D's generated media-query variant flips the tokens — derived 1:1 from the token
sheet's .dark block by scripts/gen-jx-auto-dark.mjs (single source; the parity suite fails on drift). An explicit .dark always wins, .jx-light islands stay light:
<!-- OS-follow dark with ZERO JS — the generated Part D:
tokens flip under prefers-color-scheme: dark; an explicit
.dark always wins; .jx-light islands stay light -->
<html class="jx-pure jx-auto-dark">
…
</html>Prefer a theme toggle over OS-follow? The host's own 3-line bootstrap remains the fully-JS route:
const sysDark = matchMedia('(prefers-color-scheme: dark)').matches;
document.documentElement.classList.toggle('dark', sysDark);
// ^ the host's OWN bootstrap — jx-pure deliberately ships no JS (Codex D4)demo
CustomElement — the shadow-root adoption
Document css never crosses the shadow boundary, so a CustomElement brings the two sheets ITSELF: inline the registry copies' text (bundled ?raw here) into <style> nodes inside the shadow root — style nodes parse tolerantly where constructable sheets would throw on the token sheet's build-time at-rules. The fixture below is LIVE — a real <jx-pure-island> element defined by this page, carrying the real token + face sheets this site runs. Fonts stay document-level (@font-face is document-scoped; the shadow inherits the loaded families).
// a CustomElement adopting the face inside its own shadow root
// (document css never crosses the boundary — bring the two sheets):
const style = document.createElement('style');
// tokenCss/pureCss = the two registry files' text (bundled ?raw, or
// fetched from resolved URLs — beware: dev-time ?url serves a JS
// module, not the css text)
style.textContent = tokenCss.replace(/^@import.*$/gm, '') + pureCss;
this.shadowRoot.append(style);
// ^ a <style> node, NOT replaceSync: constructable sheets THROW on the
// token sheet's build-time at-rules (@theme/@custom-variant), while a
// style node parses tolerantly. Strip the fontsource @imports (bare
// specifiers cannot resolve in shadow css; fonts are document-scoped)Resource note: inject as <style> nodes, not
constructable sheets — replaceSync throws on the
token sheet's build-time at-rules while a style node parses tolerantly; strip the
fontsource @imports (bare specifiers cannot resolve
inside a shadow style; fonts belong to the document anyway).
law
Scope laws
The contract edges, so nothing surprises you later.
Opt-in is structural
Everything rides :where(.jx-pure) inside @layer components — the scope class contributes zero
specificity, so Tailwind utilities and any unlayered author css override it cheaply.
Outside the wrapper the UA paint stands (see the buttons section's contrast column).
same .jx-pure subtree, one Tailwind class on the second button — the utilities layer beats the components layer regardless of source order.
Shadow DOM needs its own import
Document css never crosses the shadow boundary — the live adoption fixture is the CustomElement section above.
The reverse scope — no-jx-pure
Inside .jx-pure EVERYTHING is jx (select included —
the r1 opt-in stance is overruled). Mount no-jx-pure on any element and the FACE steps aside for it and its whole subtree — via :not(.no-jx-pure, .no-jx-pure *) on every face
rule, so YOUR OWN authoring there (utilities, inline styles, third-party css)
is untouched, and the opt-in class vocabulary still works (see the select
demo in Forms).
The type allowlist
Text-like styling catches ONLY the 13 text types + no-type inputs. hidden / file / checkbox / radio / range / color / button-family are never caught by the box law — they have their own lanes or stay native.
Deprecated: native-form → jx-pure
The native-form sheet lives on verbatim as Part A of this file. The native-form registry item is a same-source alias for
one release window (old target @lib/native-form.css);
input / range / number-input now declare @jixoai/jx-pure.
Still deferred
Select popup internals; floating surfaces (dialog / popover / tooltip — Tier-2 territory); disclosure open/close animation; input repaints beyond the allowlist; the Firefox/WebKit measured matrix (authored laws + forced-colors fallbacks are in place — the engine table states exactly what is verified). Forced-colors: custom-painted controls revert to appearance:auto so the system palette speaks.
Focus is the host's law
jx-pure paints focus rings only where repainting would otherwise destroy them (checkbox / radio / range / color / summary / lanes). Plain buttons and links keep the host's focus law — the site's base layer here, the UA ring on static pages.