* Generate was washed out on light and the fade downwards was why. Light's accent carries WHITE text, which caps how bright the fill can go before the label starts disappearing into it -- so the button sits AT the accent now and DARKENS under the pointer, where white only reads better. Dark's accent carries near-black text and has no such ceiling, so it does the opposite: rest at the accent, lighter on hover. Measured in both, at rest and hovered: no gradient stop under 4:1. * A section label sat directly on the dividing line above it -- the collapsible's body had no top padding of its own, so "APPEARANCE" read as belonging to the divider rather than to the card under it. * A checkbox in this app is a switch with a sentence under it, not a tick in a list. At 4px of padding the label and its hint sat hard against the top and bottom of their card, and a hint wrapping to two lines had nowhere to wrap into. * Row content is weighted to the left now: hard against the border, a card read as leaning, because what sits opposite a control is usually the short half of a wrapped line rather than anything at all. And one regression caught in the screenshot: the settings row stacks below a CONTAINER width, and that threshold was written as 300px -- which happened to be just above what the properties column resolved to. Trimming 4px of padding off two nested boxes widened it past the line, and every setting in that column went back to being shredded, in a commit about something else. It is 360 now, which is what the numbers say it should always have been: a 180px control column needs at least as much again beside it.
134 lines
6.3 KiB
CSS
134 lines
6.3 KiB
CSS
/* The native input stays in the DOM -- it carries the state, the keyboard
|
|
* behaviour and the accessibility -- but it is invisible; .cx-check-box is what
|
|
* you see. Hiding it with opacity rather than display:none keeps it focusable. */
|
|
.cx-check-input, .cx-radio-input, .cx-toggle-input {
|
|
position: absolute; opacity: 0; width: 0; height: 0; margin: 0;
|
|
}
|
|
|
|
.cx-check { display: inline-flex; }
|
|
.cx-check-box {
|
|
width: 16px; height: 16px; flex: none;
|
|
border: var(--bw) solid var(--line); border-radius: var(--r-2);
|
|
background: var(--elev-2);
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
transition: background var(--dur-1) var(--ease-standard), border-color var(--dur-1) var(--ease-standard);
|
|
}
|
|
.cx-check-box::after {
|
|
content: ""; width: 9px; height: 5px;
|
|
border-left: 2px solid var(--on-accent); border-bottom: 2px solid var(--on-accent);
|
|
transform: rotate(-45deg) translateY(-1px) scale(.6);
|
|
opacity: 0; transition: opacity var(--dur-1) var(--ease-standard), transform var(--dur-1) var(--ease-standard);
|
|
}
|
|
.cx-check-input:checked + .cx-check-face .cx-check-box { background: var(--accent); border-color: var(--accent); }
|
|
.cx-check-input:checked + .cx-check-face .cx-check-box::after { opacity: 1; transform: rotate(-45deg) translateY(-1px) scale(1); }
|
|
.cx-check-input:indeterminate + .cx-check-face .cx-check-box { background: var(--accent); border-color: var(--accent); }
|
|
.cx-check-input:indeterminate + .cx-check-face .cx-check-box::after {
|
|
opacity: 1; width: 8px; height: 0; border-bottom: 2px solid var(--on-accent);
|
|
border-left: 0; transform: none;
|
|
}
|
|
.cx-check-input:focus-visible + .cx-check-face .cx-check-box { border-color: var(--accent); box-shadow: var(--focus-ring); }
|
|
.cx-check-input:disabled + .cx-check-face .cx-check-box { opacity: var(--disabled-opacity); }
|
|
|
|
/* The input sits alongside its label, not inside it -- see choice.js. The row
|
|
* is the positioning context; the .cx-check-face label is what you click. */
|
|
.cx-check-row, .cx-radio, .cx-toggle-row { position: relative; }
|
|
/* Room around the words. A checkbox in this app is a switch with a sentence
|
|
under it, not a tick in a list: at 4px the label and its explanation sat hard
|
|
against the top and bottom of the card they are in, and a hint that wrapped
|
|
to two lines had nowhere to wrap into. */
|
|
.cx-check-face {
|
|
display: flex; align-items: flex-start; gap: var(--sp-4);
|
|
cursor: pointer; padding: var(--sp-4) 0;
|
|
}
|
|
.cx-toggle-face { align-items: center; justify-content: space-between; gap: var(--sp-6); }
|
|
/* min-inline-size, or a long word in a hint pushes the row wider than the panel
|
|
it is in instead of wrapping. */
|
|
.cx-check-text { display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; }
|
|
.cx-check-label { font-size: var(--fs-4); line-height: var(--lh-4); color: var(--text); }
|
|
.cx-checklist {
|
|
display: flex; flex-direction: column;
|
|
max-height: 200px; overflow-y: auto;
|
|
border: var(--bw) solid var(--line); border-radius: var(--r-3);
|
|
padding: var(--sp-3) var(--sp-4);
|
|
}
|
|
|
|
.cx-radio-group { display: flex; gap: var(--sp-4); }
|
|
.cx-radio-vertical { flex-direction: column; gap: var(--sp-2); }
|
|
.cx-radio-dot {
|
|
width: 16px; height: 16px; flex: none; border-radius: var(--r-pill);
|
|
border: var(--bw) solid var(--line); background: var(--elev-2);
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
}
|
|
.cx-radio-dot::after {
|
|
content: ""; width: 8px; height: 8px; border-radius: var(--r-pill);
|
|
background: var(--accent); transform: scale(0);
|
|
transition: transform var(--dur-1) var(--ease-standard);
|
|
}
|
|
.cx-radio-input:checked + .cx-check-face .cx-radio-dot { border-color: var(--accent); }
|
|
.cx-radio-input:checked + .cx-check-face .cx-radio-dot::after { transform: scale(1); }
|
|
.cx-radio-input:focus-visible + .cx-check-face .cx-radio-dot { border-color: var(--accent); box-shadow: var(--focus-ring); }
|
|
|
|
.cx-select-md { height: var(--ctl-h-lg); padding: 0 var(--ctl-pad-x-md); font-size: var(--fs-4); }
|
|
.cx-select-sm { height: var(--ctl-h-md); padding: 0 var(--ctl-pad-x-sm); font-size: var(--fs-5); }
|
|
|
|
.cx-segmented {
|
|
display: inline-flex; border: var(--bw) solid var(--line);
|
|
border-radius: var(--ctl-r); overflow: hidden; background: var(--elev-2);
|
|
}
|
|
.cx-segment {
|
|
border: 0; background: transparent; color: var(--muted);
|
|
cursor: pointer; font-family: var(--font-ui);
|
|
border-left: var(--bw) solid var(--line);
|
|
transition: background var(--dur-1) var(--ease-standard), color var(--dur-1) var(--ease-standard);
|
|
}
|
|
.cx-segment:first-child { border-left: 0; }
|
|
.cx-segmented-md .cx-segment { height: var(--ctl-h-lg); padding: 0 var(--ctl-pad-x-lg); font-size: var(--fs-5); }
|
|
.cx-segmented-sm .cx-segment { height: var(--ctl-h-md); padding: 0 var(--ctl-pad-x-md); font-size: var(--fs-6); }
|
|
.cx-segment:hover { background: var(--hover); color: var(--text); }
|
|
.cx-segment.cx-on { background: var(--accent-soft); color: var(--accent-hi); }
|
|
|
|
|
|
.cx-toggle-track {
|
|
width: 34px; height: 20px; flex: none; border-radius: var(--r-pill);
|
|
background: var(--line); position: relative;
|
|
transition: background var(--dur-1) var(--ease-standard);
|
|
}
|
|
.cx-toggle-knob {
|
|
position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
|
|
border-radius: var(--r-pill); background: var(--elev-1);
|
|
transition: transform var(--dur-1) var(--ease-standard);
|
|
}
|
|
.cx-toggle-input:checked + .cx-check-face .cx-toggle-track { background: var(--accent); }
|
|
.cx-toggle-input:checked + .cx-check-face .cx-toggle-track .cx-toggle-knob { transform: translateX(14px); }
|
|
.cx-toggle-input:focus-visible + .cx-check-face .cx-toggle-track { box-shadow: var(--focus-ring); }
|
|
|
|
/* Colour: the swatch sized to the control height so it lines up with every
|
|
other field in a settings column, and the hex field kept narrow because six
|
|
characters in a full-width input reads as an empty box. */
|
|
.cx-swatch-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--sp-4);
|
|
}
|
|
|
|
.cx-swatch {
|
|
inline-size: var(--ctl-h-lg);
|
|
block-size: var(--ctl-h-lg);
|
|
padding: 0;
|
|
border: var(--bw) solid var(--line);
|
|
border-radius: var(--ctl-r);
|
|
background: var(--elev-1);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.cx-swatch::-webkit-color-swatch-wrapper { padding: 2px; }
|
|
.cx-swatch::-webkit-color-swatch { border: 0; border-radius: var(--r-2); }
|
|
.cx-swatch::-moz-color-swatch { border: 0; border-radius: var(--r-2); }
|
|
|
|
.cx-swatch:disabled { opacity: var(--disabled-opacity); cursor: default; }
|
|
|
|
.cx-swatch-hex {
|
|
inline-size: 10ch;
|
|
font-family: var(--font-mono);
|
|
}
|