Files
digital-garbageandClaude Sonnet 5.5 aa31b95ea5 Timeline header on one line; kit literals into tokens; Composer fits; running-state viewport test; remove Auto Montage
- Header: view toggles (Assets/Preview/Properties/Auto-hide) move to the top bar; progress, the prompt warning and scene actions (rate, upscale, interpolate) move to the row under the toolbar; the timeline head never wraps from 1000px up and never clips its controls. The top bar grows a line instead of spilling when it wraps.
- Kit: every literal pixel size in element CSS is a token (the ratchet test is now zero); Composer's text box follows the viewport; the catalogue shows the component sizes.
- test:viewport adds a fake ComfyUI queue and socket for the render-running state and asserts the header is one row.
- Auto Montage removed (button, window, code, README/docs, tests). Saved projects holding pieces it made still load: the reused flag is kept.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-06 14:28:45 +02:00

139 lines
6.9 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: var(--sp-7); height: var(--sp-7); 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: var(--tick-w); height: var(--tick-h);
border-left: var(--bw-2) solid var(--on-accent); border-bottom: var(--bw-2) 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: var(--sp-4); height: 0; border-bottom: var(--bw-2) 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: var(--sp-1); 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: var(--listbox-max-h); 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: var(--sp-7); height: var(--sp-7); 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: var(--sp-4); height: var(--sp-4); 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);
/* In a narrow column the last choices wrapped out of sight (clipped by the overflow): wrap them to a second line instead. */
flex-wrap: wrap; max-inline-size: 100%;
}
.cx-segment {
border: 0; background: transparent; color: var(--muted); white-space: nowrap;
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 { padding: var(--sp-1); gap: var(--sp-1); }
.cx-segmented-sm .cx-segment { height: var(--ctl-h-sm); padding: 0 var(--ctl-pad-x-md); font-size: var(--fs-6); border-left: 0; border-radius: var(--r-2); }
.cx-segment:hover { background: var(--hover); color: var(--text); }
.cx-segment.cx-on { background: var(--accent-soft); color: var(--accent-text); }
.cx-toggle-track {
width: var(--toggle-w); height: var(--sp-8); 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: var(--sp-1); left: var(--sp-1); width: var(--sp-7); height: var(--sp-7);
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(calc(var(--toggle-w) - var(--sp-7) - 2 * var(--sp-1))); }
.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: var(--sp-1); }
.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);
}
.cx-segment.cx-on { font-weight: var(--fw-semibold); }